From ef4934417bbfa3ce26e228c742f17a6e0f0b2fd2 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 24 Aug 2018 04:56:00 -0300 Subject: [PATCH] add unallowed chars slashing mechanism --- contracts/common/MerkleProof.sol | 59 +++++++++++++++++++++ contracts/registry/ENSSubdomainRegistry.sol | 51 +++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 contracts/common/MerkleProof.sol diff --git a/contracts/common/MerkleProof.sol b/contracts/common/MerkleProof.sol new file mode 100644 index 0000000..4c30de0 --- /dev/null +++ b/contracts/common/MerkleProof.sol @@ -0,0 +1,59 @@ +pragma solidity ^0.4.24; + + +/* + * @title MerkleProof + * @dev Merkle proof verification based on + * https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol + */ +library MerkleProof { + /* + * @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves + * and each pair of pre-images is sorted. + * @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree + * @param _root Merkle root + * @param _leaf Leaf of Merkle tree + */ + function verifyProof( + bytes32[] _proof, + bytes32 _root, + bytes32 _leaf + ) + internal + pure + returns (bool) + { + bytes32 computedHash = _leaf; + + for (uint256 i = 0; i < _proof.length; i++) { + bytes32 proofElement = _proof[i]; + + if (computedHash < proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); + } + } + + // Check if the computed hash (root) is equal to the provided root + return computedHash == _root; + } +} + + © 2018 GitHub, Inc. + Terms + Privacy + Security + Status + Help + + Contact GitHub + API + Training + Shop + Blog + About + +Press h to open a hovercard with more details. diff --git a/contracts/registry/ENSSubdomainRegistry.sol b/contracts/registry/ENSSubdomainRegistry.sol index 2ccb478..3b5d35f 100644 --- a/contracts/registry/ENSSubdomainRegistry.sol +++ b/contracts/registry/ENSSubdomainRegistry.sol @@ -1,5 +1,6 @@ pragma solidity ^0.4.23; +import "../common/MerkleProof.sol"; import "../common/Controlled.sol"; import "../token/ERC20Token.sol"; import "../ens/ENS.sol"; @@ -19,7 +20,8 @@ contract ENSSubdomainRegistry is Controlled { uint256 public releaseDelay = 365 days; mapping (bytes32 => Domain) public domains; mapping (bytes32 => Account) public accounts; - + bytes32 public unallowedCharactersMerkleRoot; + event FundsOwner(bytes32 indexed subdomainhash, address fundsOwner); event DomainPrice(bytes32 indexed namehash, uint256 price); event DomainMoved(bytes32 indexed namehash, address newRegistry); @@ -52,6 +54,7 @@ contract ENSSubdomainRegistry is Controlled { ERC20Token _token, ENS _ens, PublicResolver _resolver, + bytes32 _unallowedCharactersMerkleRoot, address _parentRegistry ) public @@ -59,6 +62,7 @@ contract ENSSubdomainRegistry is Controlled { token = _token; ens = _ens; resolver = _resolver; + unallowedCharactersMerkleRoot = _unallowedCharactersMerkleRoot; parentRegistry = _parentRegistry; } @@ -167,6 +171,51 @@ contract ENSSubdomainRegistry is Controlled { emit FundsOwner(subdomainHash, msg.sender); } + + /** + * @notice removes account of invalid subdomain, and send funds to reporter + * @param _subdomain raw value of offending subdomain + * @param _offendingPos position of invalid character + * @param _rangeStart start of invalid character range + * @param _rangeEnd end of invalid character range + * @param _proof merkle proof that range is defined in merkle root + */ + function slashSubdomain( + bytes _subdomain, + bytes32 _domainHash, + uint256 _offendingPos, + uint256 _rangeStart, + uint256 _rangeEnd, + bytes32[] _proof + ) + external + { + require(_subdomain.length > _offendingPos, "Invalid position."); + + bytes32 userHash = keccak256(_subdomain); + bytes32 subdomainHash = keccak256(abi.encodePacked(_domainHash, userHash)); + require(accounts[subdomainHash].creationTime == 0, "Username not registered."); + + uint256 offendingChar = uint256(_subdomain[_offendingPos]); + require(offendingChar >= _rangeStart && offendingChar <= _rangeEnd, "Invalid range."); + require( + MerkleProof.verifyProof( + _proof, + unallowedCharactersMerkleRoot, + keccak256(abi.encodePacked(rangeStart, rangeEnd)) + ), + "Invalid Proof." + ); + + ens.setSubnodeOwner(_domainHash, userHash, address(this)); + ens.setResolver(subdomainHash, address(0)); + ens.setOwner(subdomainHash, address(0)); + + uint256 amountToTransfer = accounts[subdomainHash].tokenBalance; + delete accounts[subdomainHash]; + require(token.transfer(msg.sender, amountToTransfer), "Error in transfer."); + } + /** * @notice Migrate account to new registry * @param _userHash `msg.sender` owned subdomain hash