From ad66cb8df6a4e73affef6400149493da0e9fa150 Mon Sep 17 00:00:00 2001 From: kiba gateaux Date: Sun, 2 Jan 2022 15:05:56 +0900 Subject: [PATCH] update Root api for register/unregister and registrar integration --- packages/hardhat/contracts/Root.sol | 16 +++-- .../contracts/oracles/TrustedXNHNSOracle.sol | 11 ++++ .../contracts/registrars/HNSRegistrar.sol | 64 ++++++++++++------- packages/hardhat/contracts/registrars/SLD.sol | 0 .../hardhat/contracts/utils/Controllable.sol | 2 + packages/hardhat/interfaces/IXNHNSOracle.sol | 4 +- 6 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 packages/hardhat/contracts/registrars/SLD.sol diff --git a/packages/hardhat/contracts/Root.sol b/packages/hardhat/contracts/Root.sol index dc65f4d..09b9a96 100644 --- a/packages/hardhat/contracts/Root.sol +++ b/packages/hardhat/contracts/Root.sol @@ -23,35 +23,41 @@ contract Root is } function setResolver(address resolver) external onlyOwner { - ens.setResolver(ROOT_NODE, resolver); + ens.setResolver(ROOT_NODE, resolver); } - function register(uint id, address _owner) external onlyController returns(bool) { + function register(bytes32 label, address _owner) external onlyController returns(bool) { + uint id = generateID(label); require(address(0) == tldControllers[id], 'Cannot register claimed TLD'); if(_exists(id)) { // Name was previously owned _burn(id); } _mint(_owner, id); - ens.setSubnodeOwner(ROOT_NODE, bytes32(id), _owner); + ens.setSubnodeOwner(ROOT_NODE, label, _owner); emit TLDRegistered(id, _owner); tldControllers[id] = msg.sender; return true; } - function unregister(uint id) external onlyController returns(bool) { + function unregister(bytes32 label) external onlyController returns(bool) { + uint id = generateID(label); require(address(0) != tldControllers[id], 'Cannot unregister a nonexistant TLD'); require(msg.sender == tldControllers[id], 'Controller not allowed for NFTLD'); address _owner = ownerOf(id); if(_exists(id)) { _burn(id); } - ens.setSubnodeOwner(ROOT_NODE, bytes32(id), address(0)); // or address(this)? + ens.setSubnodeOwner(ROOT_NODE, label, address(0)); delete tldControllers[id]; emit TLDUnregistered(id, _owner); return true; } + function generateID(bytes32 label) internal pure returns (uint) { + return uint(keccak256(abi.encode(ROOT_NODE, label))); + } + /** * @dev Reclaim ownership of a name in ENS if you own the NFT. */ diff --git a/packages/hardhat/contracts/oracles/TrustedXNHNSOracle.sol b/packages/hardhat/contracts/oracles/TrustedXNHNSOracle.sol index 5d80fb2..78f74d3 100644 --- a/packages/hardhat/contracts/oracles/TrustedXNHNSOracle.sol +++ b/packages/hardhat/contracts/oracles/TrustedXNHNSOracle.sol @@ -18,6 +18,11 @@ contract TrustedXNHNSOracle is IXNHNSOracle, Ownable { NAMESPACE = _namespace; } + + /** + * @dev Optimisitically approves requesters for TLD ownership. + * @param tld string of HNS tld to verify ownership of + */ function requestTLDUpdate(string calldata tld) external override @@ -31,6 +36,12 @@ contract TrustedXNHNSOracle is IXNHNSOracle, Ownable { return node; } + /** + * @dev Allows oracle owner to update TLD ownership. + Only needed if malicious actor calls requestTLDUpdate on TLD they don't own + * @param node ENS hash of tld to claim + * @param owner_ address to give TLD to + */ function receiveTLDUpdate(bytes32 node, address owner_) external override onlyOwner diff --git a/packages/hardhat/contracts/registrars/HNSRegistrar.sol b/packages/hardhat/contracts/registrars/HNSRegistrar.sol index 9ccb7d8..b974126 100644 --- a/packages/hardhat/contracts/registrars/HNSRegistrar.sol +++ b/packages/hardhat/contracts/registrars/HNSRegistrar.sol @@ -14,16 +14,20 @@ contract HNSRegistrar { using SafeMath for uint256; ENS public ens; - // IPanvalaMember public hnsFund; + bytes32 constant private ROOT_NODE = bytes32(0); // oracle that requests and stores tld verification data IXNHNSOracle public xnhnsOracle; + // namespace that this contract lives in // formal registry of namespaces tbd in a HIP string public NAMESPACE; + // add versioning var too? + uint256 public constant snitchDeposit = 0.1 ether; uint256 public constant minTLDDeposit = 0.1 ether; + // total tld + snitch deposits in contract uint256 public totalDeposits; @@ -42,6 +46,7 @@ contract HNSRegistrar { event NewOwner(bytes32 indexed node, address owner); event SnitchedOn(bytes32 indexed node, address indexed owner, address snitch, uint256 snitchReward); event SnitchesGotStitches(bytes32 indexed node, address indexed owner, address snitch, uint256 snitchPenalty); + event FeesCollected(uint indexed fees, address indexed owner); struct Snitch { address addr; @@ -93,18 +98,20 @@ contract HNSRegistrar { * @dev Claims a name by proving ownership of its HNS equivalent. * Chainlink node verifies that NS record is pointed to namespace of this contract (Ethereum) * and pulls TXT record with address to give ownership to. - * @param node The HNS domain to claim + * @param tld The HNS domain to claim */ - function register(bytes32 node) public returns (uint id) { + function register(string calldata tld) public returns (bool) { + bytes32 node = _getNamehash(tld); require(tldDeposits[node] >= minTLDDeposit, 'Insufficient deposit for TLD'); address tldOwner = IXNHNSOracle(xnhnsOracle).getTLDOwner(node); require(tldOwner != address(0), 'Invalid TLD in namespace'); require(tldOwner == msg.sender, 'Only TLD owner can register'); Root nftld = _getRoot(); - nftld.register(uint(node), tldOwner); + nftld.register(_getLabel(tld), tldOwner); emit NewOwner(node, tldOwner); - return uint(node); + + return true; } function increaseDeposit(bytes32 node, uint256 amount) public payable returns (bool) { @@ -137,7 +144,8 @@ contract HNSRegistrar { return IXNHNSOracle(xnhnsOracle).requestTLDUpdate(tld); } - function claimSnitchReward(bytes32 node) public returns (bool) { + function claimSnitchReward(string calldata tld) public returns (bool) { + bytes32 node = _getNamehash(tld); (address addr, uint256 startTime) = _getSnitch(node); // prevent snitch front running oracle response require(block.timestamp > startTime.add(2 hours), 'Cant snitch yet'); @@ -146,7 +154,7 @@ contract HNSRegistrar { address owner = _getRoot().ownerOf(uint(node)); if(IXNHNSOracle(xnhnsOracle).getTLDOwner(node) == address(0)) { // snitch successful - uint256 tldDeposit = _unregister(node); + uint256 tldDeposit = _unregister(tld); totalDeposits = totalDeposits.sub( snitchDeposit.add(tldDeposit) ); payable(addr).transfer( snitchDeposit.add(tldDeposit.div(2)) ); emit SnitchedOn(node, owner, addr, tldDeposit.div(2)); @@ -159,19 +167,20 @@ contract HNSRegistrar { } } - function unregister(bytes32 node) public payable { + function unregister(string calldata tld) public payable { + bytes32 node = _getNamehash(tld); uint id = uint(node); address owner = _getRoot().ownerOf(id); require(msg.sender == owner, 'Only NFTLD owner can unregister'); - uint256 deposit = _unregister(node); + uint256 deposit = _unregister(tld); payable(owner).transfer(deposit); } - function _unregister(bytes32 node) internal returns (uint256 deposit) { - _getRoot().unregister(uint(node)); - deposit = tldDeposits[node]; - delete tldDeposits[node]; + function _unregister(string memory tld) internal returns (uint256 deposit) { + _getRoot().unregister(_getLabel(tld)); + deposit = tldDeposits[_getNamehash(tld)]; + delete tldDeposits[_getNamehash(tld)]; totalDeposits = totalDeposits.sub(deposit); return deposit; } @@ -179,10 +188,11 @@ contract HNSRegistrar { /** * @dev donate fees collected by registrar to HNS Fund via Panvala League */ - function donateProfits() public returns(uint) { + function claimFees() external returns(bool) { uint feesCollected = address(this).balance.sub(totalDeposits) ; - // hnsFund.regenerate.value(feesCollected)(feesCollected); - return feesCollected; + payable(_getRoot().owner()).call{value: feesCollected}; + emit FeesCollected(feesCollected, _getRoot().owner()); + return true; } /** Getter Functions */ @@ -194,16 +204,23 @@ contract HNSRegistrar { function namespace() public view returns (string memory) { return NAMESPACE; } + + function getLabel(string memory tld) external pure returns (bytes32) { + return _getLabel(tld); + } + function _getLabel(string memory tld) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(tld)); + } - function _getNamehash(string memory tld) public pure returns (bytes32) { - return keccak256(abi.encodePacked( - bytes32(0), - keccak256(abi.encodePacked(tld)) - )); + function getNamehash(string memory tld) external pure returns (bytes32) { + return _getNamehash(tld); + } + function _getNamehash(string memory tld) internal pure returns (bytes32) { + return keccak256(abi.encodePacked( ROOT_NODE, _getLabel(tld) )); } function _getRoot() internal view returns (Root) { - return Root(ens.owner(bytes32(0))); + return Root(ens.owner(ROOT_NODE)); } function _getSnitch(bytes32 node) public view returns (address, uint256) { @@ -211,11 +228,10 @@ contract HNSRegistrar { return (_snitch.addr, _snitch.startTime); } - function _registrarEnabled() internal returns (bool) { + function _registrarEnabled() internal view returns (bool) { return IXNHNSOracle(xnhnsOracle).getCallerPermission(address(this)); } - function supportsInterface(bytes4 interfaceID) public pure returns (bool) { return interfaceID == INTERFACE_META_ID || interfaceID == XNHNS_CLAIM_ID; diff --git a/packages/hardhat/contracts/registrars/SLD.sol b/packages/hardhat/contracts/registrars/SLD.sol new file mode 100644 index 0000000..e69de29 diff --git a/packages/hardhat/contracts/utils/Controllable.sol b/packages/hardhat/contracts/utils/Controllable.sol index 6c54f10..ce48929 100644 --- a/packages/hardhat/contracts/utils/Controllable.sol +++ b/packages/hardhat/contracts/utils/Controllable.sol @@ -3,6 +3,7 @@ pragma solidity ^0.7.0; import "@openzeppelin/contracts/access/Ownable.sol"; contract Controllable is Ownable { + // TODO change so its address -> bytes32 and we can scope controllers to specific domains mapping(address=>bool) public controllers; event ControllerChanged(address indexed controller, bool enabled); @@ -13,6 +14,7 @@ contract Controllable is Ownable { } function setController(address controller, bool enabled) public onlyOwner { + // TODO check address is owner of node controllers[controller] = enabled; emit ControllerChanged(controller, enabled); } diff --git a/packages/hardhat/interfaces/IXNHNSOracle.sol b/packages/hardhat/interfaces/IXNHNSOracle.sol index 96da612..357385d 100644 --- a/packages/hardhat/interfaces/IXNHNSOracle.sol +++ b/packages/hardhat/interfaces/IXNHNSOracle.sol @@ -7,8 +7,8 @@ interface IXNHNSOracle { function requestTLDUpdate(string calldata tld) external returns (bytes32); function receiveTLDUpdate(bytes32, address) external returns (bool); - function getTLDOwner(bytes32 node) external returns (address); - function getCallerPermission(address addr) external returns (bool); + function getTLDOwner(bytes32 node) external view returns (address); + function getCallerPermission(address addr) external view returns (bool); function setCallerPermission(address addr, bool permission) external returns (bool); function setOracle(address oracle, uint fee, bytes32 jobId) external returns (bool); }