This repository has been archived by the owner on Nov 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from rnsdomains/fifs-with-addr
Fifs with addr
- Loading branch information
Showing
10 changed files
with
1,264 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
pragma solidity ^0.5.3; | ||
|
||
import "@rsksmart/rns-registry/contracts/AbstractRNS.sol"; | ||
import "@rsksmart/rns-resolver/contracts/AbstractAddrResolver.sol"; | ||
import "./FIFSRegistrarBase.sol"; | ||
import "./PricedContract.sol"; | ||
|
||
/// @title First-in first-served registrar with automatic addr setup. | ||
/// @notice You can use this contract to register names in RNS with addr | ||
/// resolution set automatcially. | ||
/// @dev This contract has permission to register in Node Owner. | ||
contract FIFSAddrRegistrar is FIFSRegistrarBase, PricedContract { | ||
address pool; | ||
AbstractRNS rns; | ||
bytes32 rootNode; | ||
|
||
// sha3('register(string,address,bytes32,uint,address)') | ||
bytes4 constant REGISTER_SIGNATURE = 0x5f7b99d5; | ||
|
||
constructor ( | ||
ERC677 _rif, | ||
NodeOwner _nodeOwner, | ||
address _pool, | ||
AbstractNamePrice _namePrice, | ||
AbstractRNS _rns, | ||
bytes32 _rootNode | ||
) public FIFSRegistrarBase(_rif, _nodeOwner) PricedContract(_namePrice) { | ||
pool = _pool; | ||
rns = _rns; | ||
rootNode = _rootNode; | ||
} | ||
|
||
/* | ||
3. Execute registration via: | ||
- ERC-20 with approve() + register() | ||
- ERC-677 with transferAndCall() | ||
The price of a domain is given by name price contract. | ||
*/ | ||
|
||
// - Via ERC-20 | ||
/// @notice Registers a .rsk name in RNS. | ||
/// @dev This method must be called after commiting. | ||
/// @param name The name to register. | ||
/// @param nameOwner The owner of the name to regiter. | ||
/// @param secret The secret used to make the commitment. | ||
/// @param duration Time to register in years. | ||
/// @param addr Address to set as addr resolution. | ||
function register( | ||
string calldata name, | ||
address nameOwner, | ||
bytes32 secret, | ||
uint duration, | ||
address addr | ||
) external { | ||
uint cost = executeRegistration(name, nameOwner, secret, duration, addr); | ||
require(rif.transferFrom(msg.sender, pool, cost), "Token transfer failed"); | ||
} | ||
|
||
// - Via ERC-677 | ||
/* Encoding: | ||
| signature | 4 bytes - offset 0 | ||
| owner | 20 bytes - offset 4 | ||
| secret | 32 bytes - offest 24 | ||
| duration | 32 bytes - offset 56 | ||
| duration | 20 bytes - offset 88 | ||
| name | variable size - offset 108 | ||
*/ | ||
|
||
/// @notice ERC-677 token fallback function. | ||
/// @dev Follow 'Register encoding' to execute a one-transaction regitration. | ||
/// @param from token sender. | ||
/// @param value amount of tokens sent. | ||
/// @param data data associated with transaction. | ||
/// @return true if successfull. | ||
function tokenFallback(address from, uint value, bytes calldata data) external returns (bool) { | ||
require(msg.sender == address(rif), "Only RIF token"); | ||
require(data.length > 108, "Invalid data"); | ||
|
||
bytes4 signature = data.toBytes4(0); | ||
|
||
require(signature == REGISTER_SIGNATURE, "Invalid signature"); | ||
|
||
address nameOwner = data.toAddress(4); | ||
bytes32 secret = data.toBytes32(24); | ||
uint duration = data.toUint(56); | ||
address addr = data.toAddress(88); | ||
string memory name = data.toString(108, data.length.sub(108)); | ||
|
||
registerWithToken(name, nameOwner, secret, duration, from, value, addr); | ||
|
||
return true; | ||
} | ||
|
||
function registerWithToken( | ||
string memory name, | ||
address nameOwner, | ||
bytes32 secret, | ||
uint duration, | ||
address from, | ||
uint amount, | ||
address addr | ||
) private { | ||
uint cost = executeRegistration(name, nameOwner, secret, duration, addr); | ||
require(amount >= cost, "Not enough tokens"); | ||
require(rif.transfer(pool, cost), "Token transfer failed"); | ||
if (amount.sub(cost) > 0) | ||
require(rif.transfer(from, amount.sub(cost)), "Token transfer failed"); | ||
} | ||
|
||
/// @notice Executes registration abstracted from payment method. | ||
/// @param name The name to register. | ||
/// @param nameOwner The owner of the name to regiter. | ||
/// @param secret The secret used to make the commitment. | ||
/// @param duration Time to register in years. | ||
/// @param addr Address to set as addr resolution. | ||
/// @return price Price of the name to register. | ||
function executeRegistration ( | ||
string memory name, | ||
address nameOwner, | ||
bytes32 secret, | ||
uint duration, | ||
address addr | ||
) private returns (uint) { | ||
bytes32 label = keccak256(abi.encodePacked(name)); | ||
uint256 tokenId = uint256(label); | ||
|
||
require(name.strlen() >= minLength, "Short names not available"); | ||
|
||
bytes32 commitment = makeCommitment(label, nameOwner, secret); | ||
require(canReveal(commitment), "No commitment found"); | ||
commitmentRevealTime[commitment] = 0; | ||
|
||
nodeOwner.register(label, address(this), duration.mul(365 days)); | ||
|
||
AbstractAddrResolver(rns.resolver(rootNode)) | ||
.setAddr( | ||
keccak256(abi.encodePacked(rootNode, label)), | ||
addr | ||
); | ||
|
||
nodeOwner.reclaim(tokenId, nameOwner); | ||
nodeOwner.transferFrom(address(this), nameOwner, tokenId); | ||
|
||
return price(name, nodeOwner.expirationTime(uint(label)), duration); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
pragma solidity ^0.5.3; | ||
|
||
import "@openzeppelin/contracts/math/SafeMath.sol"; | ||
import "@ensdomains/ethregistrar/contracts/StringUtils.sol"; | ||
import "@rsksmart/erc677/contracts/ERC677.sol"; | ||
import "@rsksmart/erc677/contracts/ERC677TransferReceiver.sol"; | ||
import "./NodeOwner.sol"; | ||
import "./AbstractNamePrice.sol"; | ||
import "./BytesUtils.sol"; | ||
|
||
|
||
/// @title First-in first-served registrar base. | ||
/// @notice This is an abstract contract. A Registrar can inherit from | ||
/// this contract to implement basic commit-reveal and admin functionality. | ||
/// @dev Inherited contract should have registrar permission in Node Owner. | ||
contract FIFSRegistrarBase is ERC677TransferReceiver, Ownable { | ||
using SafeMath for uint256; | ||
using StringUtils for string; | ||
using BytesUtils for bytes; | ||
|
||
mapping (bytes32 => uint) internal commitmentRevealTime; | ||
uint public minCommitmentAge = 1 minutes; | ||
|
||
uint public minLength = 5; | ||
|
||
ERC677 rif; | ||
NodeOwner nodeOwner; | ||
|
||
constructor ( | ||
ERC677 _rif, | ||
NodeOwner _nodeOwner | ||
) public { | ||
rif = _rif; | ||
nodeOwner = _nodeOwner; | ||
} | ||
|
||
/////////////////// | ||
// COMMIT-REVEAL // | ||
/////////////////// | ||
|
||
/* | ||
0. Caclulate makeCommitment hash of the domain to be registered (off-chain) | ||
1. Commit the calculated hash | ||
2. Wait minCommitmentAge | ||
3. Execute registration via inheriting contract. | ||
*/ | ||
|
||
// 0. | ||
/// @notice Create a commitment for register action. | ||
/// @dev Don't use this method on-chain when commiting. | ||
/// @param label keccak256 of the name to be registered. | ||
/// @param nameOwner Owner of the name to be registered. | ||
/// @param secret Secret to protect the name to be registered. | ||
/// @return The commitment hash. | ||
function makeCommitment (bytes32 label, address nameOwner, bytes32 secret) public pure returns (bytes32) { | ||
return keccak256(abi.encodePacked(label, nameOwner, secret)); | ||
} | ||
|
||
// 1. | ||
/// @notice Commit before registring a name. | ||
/// @dev A valid commitment can be calculated using makeCommitment off-chain. | ||
/// @param commitment A valid commitment hash. | ||
function commit(bytes32 commitment) external { | ||
require(commitmentRevealTime[commitment] < 1, "Existent commitment"); | ||
commitmentRevealTime[commitment] = now.add(minCommitmentAge); | ||
} | ||
|
||
// 2. | ||
/// @notice Ensure the commitment is ready to be revealed. | ||
/// @dev This method can be polled to ensure registration. | ||
/// @param commitment Commitment to be queried. | ||
/// @return Wether the commitment can be revealed or not. | ||
function canReveal(bytes32 commitment) public view returns (bool) { | ||
uint revealTime = commitmentRevealTime[commitment]; | ||
return 0 < revealTime && revealTime <= now; | ||
} | ||
|
||
///////////////////// | ||
// REGISTRAR ADMIN // | ||
///////////////////// | ||
|
||
/// @notice Change required commitment maturity. | ||
/// @dev Only owner. | ||
/// @param newMinCommitmentAge The new maturity required. | ||
function setMinCommitmentAge (uint newMinCommitmentAge) external onlyOwner { | ||
minCommitmentAge = newMinCommitmentAge; | ||
} | ||
|
||
/// @notice Change disbaled names. | ||
/// @dev Only owner. | ||
/// @param newMinLength The new minimum length enabled. | ||
function setMinLength (uint newMinLength) external onlyOwner { | ||
minLength = newMinLength; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.