Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Names): Stop Burning MANA when registering a Name #38

Merged
merged 14 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 8 additions & 27 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
version: 2
version: 2.1
orbs:
node: circleci/node@5.1.0
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/node:8.11.3

working_directory: ~/repo

- image: 'cimg/base:stable'
steps:
- checkout

# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package-lock.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-

- run:
name: Install packages
command: npm install

- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package-lock.json" }}

# run tests!
- run:
name: Run tests
command: npm run test
- node/install:
node-version: '16.19.0'
- run: npm ci
- run: npm run test
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ETHERSCAN_KEY="some-key"
RPC_URL="http://some-rpc-url.org"
NETWORK="GOERLI"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ cache
coverage
coverage.json
.vscode
.env
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

### Mainnet

## Update 04/04/2023

- DCLControllerV2 = `0xbe92b49aee993adea3a002adcda189a2b7dec56c`

## Update 07/10/2020

- ENS Public Resolver = `0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41`
Expand All @@ -22,6 +26,10 @@
- ENS Base Registrar = `0xfac7bea255a6990f749363002136af6556b31e04`
- ENS Registrar Controller = `0xb22c1c159d12461ea124b0deb4b5b93020e6ad16`

### Goerli

- DCLControllerV2 - `0xe23b047c8ee33d0c423676544bca6d2c9d3faa49`

### Ropsten

- ENS Registry = `0x112234455c3a32fd11230c42e7bccd4a84e02010`
Expand Down
22 changes: 0 additions & 22 deletions buidler.config.js

This file was deleted.

116 changes: 116 additions & 0 deletions contracts/ens/DCLControllerV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@

pragma solidity ^0.5.15;

import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/utils/Address.sol";

import "../interfaces/IENSRegistry.sol";
import "../interfaces/IDCLRegistrar.sol";
import "../interfaces/IERC20Token.sol";

contract DCLControllerV2 is Ownable {
using Address for address;

// Price of each name
uint256 constant public PRICE = 100 ether;

// Accepted ERC20 token
IERC20Token public acceptedToken;
// DCL Registrar
IDCLRegistrar public registrar;
// Fee Collector
address public feeCollector;

// Emitted when a name is bought
event NameBought(address indexed _caller, address indexed _beneficiary, uint256 _price, string _name);

// Emitted when the fee collector is changed
event FeeCollectorChanged(address indexed _oldFeeCollector, address indexed _newFeeCollector);

/**
* @dev Constructor of the contract
* This contract does not support ERC20 tokens that do not revert on an invalid transfer.
* @param _acceptedToken - address of the accepted ERC20 token
* @param _registrar - address of the DCL registrar contract
* @param _feeCollector - address of the fee collector
* @param _owner - address of the contract owner
*/
constructor(IERC20Token _acceptedToken, IDCLRegistrar _registrar, address _feeCollector, address _owner) public {
require(address(_acceptedToken).isContract(), "Accepted token should be a contract");
require(address(_registrar).isContract(), "Registrar should be a contract");

// Accepted token
acceptedToken = _acceptedToken;
// DCL registrar
registrar = _registrar;

_setFeeCollector(_feeCollector);

_transferOwnership(_owner);
}

/**
* @dev Register a name
* This function transfers the PRICE from the sender to the fee collector without checking the return value of the transferFrom function.
* This means that only tokens that revert when the transfer fails due to insufficient balance or insufficient approve should be used.
* If the token does not revert on an invalid transfer, the register will succeed and a name will be minted without being paid for.
* @param _name - name to be registered
* @param _beneficiary - owner of the name
*/
function register(string memory _name, address _beneficiary) public {
// Check for valid beneficiary
require(_beneficiary != address(0), "Invalid beneficiary");

// Check if the name is valid
_requireNameValid(_name);

// Register the name
registrar.register(_name, _beneficiary);
// Transfer PRICE to the fee collector
acceptedToken.transferFrom(msg.sender, feeCollector, PRICE);
// Log
emit NameBought(msg.sender, _beneficiary, PRICE, _name);
}

/**
* @notice Set the fee collector
* @dev Only the owner can change the fee collector
* @param _feeCollector - the address of the new collector
*/
function setFeeCollector(address _feeCollector) external onlyOwner {
_setFeeCollector(_feeCollector);
}

/**
* @dev Validate a name
* @notice that only a-z is allowed
* @param _name - string for the name
*/
function _requireNameValid(string memory _name) internal pure {
bytes memory tempName = bytes(_name);
require(
tempName.length >= 2 && tempName.length <= 15,
"Name should be greater than or equal to 2 and less than or equal to 15"
);
for(uint256 i = 0; i < tempName.length; i++) {
require(_isLetter(tempName[i]) || _isNumber(tempName[i]), "Invalid Character");
}
}

function _isLetter(bytes1 _char) internal pure returns (bool) {
return (_char >= 0x41 && _char <= 0x5A) || (_char >= 0x61 && _char <= 0x7A);
}

function _isNumber(bytes1 _char) internal pure returns (bool) {
return (_char >= 0x30 && _char <= 0x39);
}

function _setFeeCollector(address _feeCollector) internal {
require(_feeCollector != address(0), "Invalid fee collector");

emit FeeCollectorChanged(feeCollector, _feeCollector);

feeCollector = _feeCollector;
}

}
4 changes: 1 addition & 3 deletions contracts/interfaces/IERC20Token.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
pragma solidity ^0.5.15;

import "openzeppelin-eth/contracts/token/ERC20/IERC20.sol";

contract IERC20Token is IERC20{
contract IERC20Token {
function balanceOf(address from) public view returns (uint256);
function transferFrom(address from, address to, uint tokens) public returns (bool);
function allowance(address owner, address spender) public view returns (uint256);
Expand Down
32 changes: 32 additions & 0 deletions contracts/mocks/FakeDCLControllerV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pragma solidity ^0.5.15;

import "../ens/DCLControllerV2.sol";


contract FakeDCLControllerV2 is DCLControllerV2 {
// ERC20
event Burn(address indexed burner, uint256 value);
// ERC721
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
// ENS Registry
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
event Transfer(bytes32 indexed node, address owner);
event NewResolver(bytes32 indexed node, address resolver);
event NewTTL(bytes32 indexed node, uint64 ttl);
// DCL Registrar
event NameRegistered(
address indexed _caller,
address indexed _beneficiary,
bytes32 indexed _labelHash,
string _subdomain,
uint256 _createdDate
);

constructor(
IERC20Token _acceptedToken,
IDCLRegistrar _registrar,
address _feeCollector,
address _owner
) public DCLControllerV2(_acceptedToken, _registrar, _feeCollector, _owner) {}

}
Loading