{
  "language": "Solidity",
  "sources": {
    "src/ens/ENSController.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/access/Guarded.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/typedData/TypedDataContainer.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\nimport \"./resolvers/ENSAddressResolver.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./resolvers/ENSPubKeyResolver.sol\";\nimport \"./resolvers/ENSTextResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n\n/**\n * @title ENS controller\n *\n * @notice ENS subnode registrar\n *\n * @dev The process of adding root node consists of 3 steps:\n * 1. `submitNode` - should be called from ENS node owner,\n * 2. Change ENS node owner in ENS registry to ENS controller,\n * 3. `verifyNode` - should be called from previous ENS node owner,\n *\n * To register sub node, `msg.sender` need to send valid signature from one of guardian key.\n * Once registration is complete `msg.sender` becoming both node owner and `addr` record value.\n *\n * After registration sub node cannot be replaced.\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract ENSController is Guarded, Initializable, TypedDataContainer, GatewayRecipient, ENSAddressResolver, ENSNameResolver, ENSPubKeyResolver, ENSTextResolver {\n  struct SubNodeRegistration {\n    address account;\n    bytes32 node;\n    bytes32 label;\n  }\n\n  bytes4 private constant INTERFACE_META_ID = bytes4(keccak256(abi.encodePacked(\"supportsInterface(bytes4)\")));\n\n  bytes32 private constant SUB_NODE_REGISTRATION_TYPE_HASH = keccak256(\n    \"SubNodeRegistration(address account,bytes32 node,bytes32 label)\"\n  );\n\n  ENSRegistry public registry;\n\n  mapping(bytes32 => address) public nodeOwners;\n\n  // events\n\n  /**\n   * @dev Emitted when the address field in node resolver is changed\n   * @param node node name hash\n   * @param addr new address\n   */\n  event AddrChanged(\n    bytes32 indexed node,\n    address addr\n  );\n\n  /**\n   * @dev Emitted when new node is submitted\n   * @param node node name hash\n   * @param owner owner address\n   */\n  event NodeSubmitted(\n    bytes32 node,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when the existing owner is verified\n   * @param node node name hash\n   */\n  event NodeVerified(\n    bytes32 node\n  );\n\n  /**\n   * @dev Emitted when new node is released\n   * @param node node name hash\n   * @param owner owner address\n   */\n  event NodeReleased(\n    bytes32 node,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when ENS registry address is changed\n   * @param registry registry address\n   */\n  event RegistryChanged(\n    address registry\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Guarded() Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `ENSController` contract\n   * @param registry_ ENS registry address\n   * @param gateway_ gateway address\n   * @param typedDataDomainNameHash hash of a typed data domain name\n   * @param typedDataDomainVersionHash hash of a typed data domain version\n   * @param typedDataDomainSalt typed data salt\n   */\n  function initialize(\n    ENSRegistry registry_,\n    address[] calldata guardians_,\n    address gateway_,\n    bytes32 typedDataDomainNameHash,\n    bytes32 typedDataDomainVersionHash,\n    bytes32 typedDataDomainSalt\n  )\n    external\n    onlyInitializer\n  {\n    require(\n      address(registry_) != address(0),\n      \"ENSController: cannot set 0x0 registry\"\n    );\n\n    registry = registry_;\n\n    // Guarded\n    _initializeGuarded(guardians_);\n\n    // GatewayRecipient\n    _initializeGatewayRecipient(gateway_);\n\n    // TypedDataContainer\n    _initializeTypedDataContainer(\n      typedDataDomainNameHash,\n      typedDataDomainVersionHash,\n      typedDataDomainSalt\n    );\n  }\n\n  /**\n   * @notice Sets registry\n   * @param registry_ registry address\n   */\n  function setRegistry(\n    ENSRegistry registry_\n  )\n    external\n    onlyGuardian\n  {\n    require(\n      address(registry_) != address(0),\n      \"ENSController: cannot set 0x0 registry\"\n    );\n\n    require(\n      registry_ != registry,\n      \"ENSController: registry already set\"\n    );\n\n    registry = registry_;\n\n    emit RegistryChanged(\n      address(registry)\n    );\n  }\n\n  /**\n   * @notice Submits node\n   * @dev Should be called from the current ENS node owner\n   * @param node node name hash\n   */\n  function submitNode(\n    bytes32 node\n  )\n    external\n  {\n    address owner = _getContextAccount();\n\n    require(\n      _addr(node) == address(0),\n      \"ENSController: node already exists\"\n    );\n\n    require(\n      nodeOwners[node] == address(0),\n      \"ENSController: node already submitted\"\n    );\n\n    require(\n      registry.owner(node) == owner,\n      \"ENSController: invalid ens node owner\"\n    );\n\n    nodeOwners[node] = owner;\n\n    emit NodeSubmitted(node, owner);\n  }\n\n  /**\n   * @notice Verifies node\n   * @dev Should be called from the previous ENS node owner\n   * @param node node name hash\n   */\n  function verifyNode(\n    bytes32 node\n  )\n    external\n  {\n    address owner = _getContextAccount();\n\n    require(\n      _addr(node) == address(0),\n      \"ENSController: node already exists\"\n    );\n\n    require(\n      nodeOwners[node] == owner,\n      \"ENSController: invalid node owner\"\n    );\n\n    require(\n      registry.owner(node) == address(this),\n      \"ENSController: invalid ens node owner\"\n    );\n\n    _setAddr(node, address(this));\n\n    registry.setResolver(node, address(this));\n\n    emit NodeVerified(node);\n  }\n\n  /**\n   * @notice Releases node\n   * @dev Should be called from the previous ENS node owner\n   * @param node node name hash\n   */\n  function releaseNode(\n    bytes32 node\n  )\n    external\n  {\n    address owner = _getContextAccount();\n\n    require(\n      _addr(node) == address(this),\n      \"ENSController: node doesn't exist\"\n    );\n\n    require(\n      nodeOwners[node] == owner,\n      \"ENSController: invalid node owner\"\n    );\n\n    registry.setOwner(node, owner);\n\n    delete nodeOwners[node];\n\n    emit NodeReleased(node, owner);\n  }\n\n  /**\n   * @notice Sync address\n   * @param node node name hash\n   */\n  function syncAddr(\n    bytes32 node\n  )\n    external\n  {\n    address account = _getContextAccount();\n\n    require(\n      account == registry.owner(node),\n      \"ENSController: caller is not the node owner\"\n    );\n\n    require(\n      registry.resolver(node) == address(this),\n      \"ENSController: invalid node resolver\"\n    );\n\n    require(\n      _addr(node) == address(0),\n      \"ENSController: node already in sync\"\n    );\n\n    _setAddr(node, account);\n  }\n\n  /**\n   * @notice Registers sub node\n   * @param node node name hash\n   * @param label label hash\n   * @param guardianSignature guardian signature\n   */\n  function registerSubNode(\n    bytes32 node,\n    bytes32 label,\n    bytes calldata guardianSignature\n  )\n    external\n  {\n    address account = _getContextAccount();\n\n    bytes32 messageHash = _hashPrimaryTypedData(\n      _hashTypedData(\n        account,\n        node,\n        label\n      )\n    );\n\n    require(\n      _verifyGuardianSignature(messageHash, guardianSignature),\n      \"ENSController: invalid guardian signature\"\n    );\n\n    bytes32 subNode = keccak256(\n      abi.encodePacked(\n        node,\n        label\n      )\n    );\n\n    require(\n      _addr(node) == address(this),\n      \"ENSController: invalid node\"\n    );\n\n    require(\n      _addr(subNode) == address(0),\n      \"ENSController: label already taken\"\n    );\n\n    registry.setSubnodeRecord(node, label, address(this), address(this), 0);\n    registry.setOwner(subNode, account);\n\n    _setAddr(subNode, account);\n  }\n\n  // external functions (pure)\n  function supportsInterface(\n    bytes4 interfaceID\n  )\n    external\n    pure\n    returns(bool)\n  {\n    return interfaceID == INTERFACE_META_ID ||\n    interfaceID == INTERFACE_ADDR_ID ||\n    interfaceID == INTERFACE_ADDRESS_ID ||\n    interfaceID == INTERFACE_NAME_ID ||\n    interfaceID == INTERFACE_PUB_KEY_ID ||\n    interfaceID == INTERFACE_TEXT_ID;\n  }\n\n  // public functions (views)\n\n  /**\n   * @notice Hashes `SubNodeRegistration` typed data\n   * @param subNodeRegistration struct\n   * @return hash\n   */\n  function hashSubNodeRegistration(\n    SubNodeRegistration memory subNodeRegistration\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashPrimaryTypedData(\n      _hashTypedData(\n        subNodeRegistration.account,\n        subNodeRegistration.node,\n        subNodeRegistration.label\n      )\n    );\n  }\n\n  // internal functions (views)\n\n  function _isNodeOwner(\n    bytes32 node\n  )\n    internal\n    override\n    view\n    returns (bool)\n  {\n    return registry.owner(node) == _getContextAccount();\n  }\n\n  // private functions (pure)\n\n  function _hashTypedData(\n    address account,\n    bytes32 node,\n    bytes32 label\n  )\n    private\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encode(\n      SUB_NODE_REGISTRATION_TYPE_HASH,\n      account,\n      node,\n      label\n    ));\n  }\n}\n"
    },
    "src/common/access/Guarded.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/SignatureLib.sol\";\n\n\n/**\n * @title Guarded\n *\n * @dev Contract module which provides a guardian-type control mechanism.\n * It allows key accounts to have guardians and restricts specific methods to be accessible by guardians only.\n *\n * Each guardian account can remove other guardians\n *\n * Use `_initializeGuarded` to initialize the contract\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Guarded {\n  using SignatureLib for bytes32;\n\n  mapping(address => bool) private guardians;\n\n  // events\n\n  /**\n   * @dev Emitted when a new guardian is added\n   * @param sender sender address\n   * @param guardian guardian address\n   */\n  event GuardianAdded(\n    address sender,\n    address guardian\n  );\n\n  /**\n   * @dev Emitted when the existing guardian is removed\n   * @param sender sender address\n   * @param guardian guardian address\n   */\n  event GuardianRemoved(\n    address sender,\n    address guardian\n  );\n\n  // modifiers\n\n  /**\n   * @dev Throws if tx.origin is not a guardian account\n   */\n  modifier onlyGuardian() {\n    require(\n      // solhint-disable-next-line avoid-tx-origin\n      guardians[tx.origin],\n      \"Guarded: tx.origin is not the guardian\"\n    );\n\n    _;\n  }\n\n  /**\n   * @dev Internal constructor\n   */\n  constructor() internal {}\n\n  // external functions\n\n  /**\n   * @notice Adds a new guardian\n   * @param guardian guardian address\n   */\n  function addGuardian(\n    address guardian\n  )\n    external\n    onlyGuardian\n  {\n    _addGuardian(guardian);\n  }\n\n  /**\n   * @notice Removes the existing guardian\n   * @param guardian guardian address\n   */\n  function removeGuardian(\n    address guardian\n  )\n    external\n    onlyGuardian\n  {\n    require(\n      // solhint-disable-next-line avoid-tx-origin\n      tx.origin != guardian,\n      \"Guarded: cannot remove self\"\n    );\n\n    require(\n      guardians[guardian],\n      \"Guarded: guardian doesn't exist\"\n    );\n\n    guardians[guardian] = false;\n\n    emit GuardianRemoved(\n      // solhint-disable-next-line avoid-tx-origin\n      tx.origin,\n      guardian\n    );\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Check if guardian exists\n   * @param guardian guardian address\n   * @return true when guardian exists\n   */\n  function isGuardian(\n    address guardian\n  )\n    external\n    view\n    returns (bool)\n  {\n    return guardians[guardian];\n  }\n\n  /**\n   * @notice Verifies guardian signature\n   * @param messageHash message hash\n   * @param signature signature\n   * @return true on correct guardian signature\n   */\n  function verifyGuardianSignature(\n    bytes32 messageHash,\n    bytes calldata signature\n  )\n    external\n    view\n    returns (bool)\n  {\n    return _verifyGuardianSignature(\n      messageHash,\n      signature\n    );\n  }\n\n  // internal functions\n\n  /**\n   * @notice Initializes `Guarded` contract\n   * @dev If `guardians_` array is empty `tx.origin` is added as guardian account\n   * @param guardians_ array of guardians addresses\n   */\n  function _initializeGuarded(\n    address[] memory guardians_\n  )\n    internal\n  {\n    if (guardians_.length == 0) {\n      // solhint-disable-next-line avoid-tx-origin\n      _addGuardian(tx.origin);\n    } else {\n      uint guardiansLen = guardians_.length;\n      for (uint i = 0; i < guardiansLen; i++) {\n        _addGuardian(guardians_[i]);\n      }\n    }\n  }\n\n\n  // internal functions (views)\n\n  function _verifyGuardianSignature(\n    bytes32 messageHash,\n    bytes memory signature\n  )\n    internal\n    view\n    returns (bool)\n  {\n    address guardian = messageHash.recoverAddress(signature);\n\n    return guardians[guardian];\n  }\n\n  // private functions\n\n  function _addGuardian(\n    address guardian\n  )\n    private\n  {\n    require(\n      guardian != address(0),\n      \"Guarded: cannot add 0x0 guardian\"\n    );\n\n    require(\n      !guardians[guardian],\n      \"Guarded: guardian already exists\"\n    );\n\n    guardians[guardian] = true;\n\n    emit GuardianAdded(\n      // solhint-disable-next-line avoid-tx-origin\n      tx.origin,\n      guardian\n    );\n  }\n}\n"
    },
    "src/common/lifecycle/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Initializable\n *\n * @dev Contract module which provides access control mechanism, where\n * there is the initializer account that can be granted exclusive access to\n * specific functions.\n *\n * The initializer account will be tx.origin during contract deployment and will be removed on first use.\n * Use `onlyInitializer` modifier on contract initialize process.\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Initializable {\n  address private initializer;\n\n  // events\n\n  /**\n   * @dev Emitted after `onlyInitializer`\n   * @param initializer initializer address\n   */\n  event Initialized(\n    address initializer\n  );\n\n  // modifiers\n\n  /**\n   * @dev Throws if tx.origin is not the initializer\n   */\n  modifier onlyInitializer() {\n    require(\n      // solhint-disable-next-line avoid-tx-origin\n      tx.origin == initializer,\n      \"Initializable: tx.origin is not the initializer\"\n    );\n\n    /// @dev removes initializer\n    initializer = address(0);\n\n    _;\n\n    emit Initialized(\n      // solhint-disable-next-line avoid-tx-origin\n      tx.origin\n    );\n  }\n\n  /**\n   * @dev Internal constructor\n   */\n  constructor()\n    internal\n  {\n    // solhint-disable-next-line avoid-tx-origin\n    initializer = tx.origin;\n  }\n\n   // external functions (views)\n\n  /**\n   * @notice Check if contract is initialized\n   * @return true when contract is initialized\n   */\n  function isInitialized()\n    external\n    view\n    returns (bool)\n  {\n    return initializer == address(0);\n  }\n}\n"
    },
    "src/common/typedData/TypedDataContainer.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Typed data container\n *\n * @dev EIP-712 is used across whole repository.\n *\n * Use `_initializeTypedDataContainer` to initialize the contract\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract TypedDataContainer {\n  string private constant TYPED_DATA_PREFIX = \"\\x19\\x01\";\n  bytes32 private constant TYPED_DATA_DOMAIN_TYPE_HASH = keccak256(\n    \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)\"\n  );\n\n  bytes32 public typedDataDomainSeparator;\n\n  /**\n   * @dev internal constructor\n   */\n  constructor() internal {}\n\n  // internal functions\n\n  /**\n   * @notice Initializes `TypedDataContainer` contract\n   * @param domainNameHash hash of a domain name\n   * @param domainVersionHash hash of a domain version\n   * @param domainSalt domain salt\n   */\n  function _initializeTypedDataContainer(\n    bytes32 domainNameHash,\n    bytes32 domainVersionHash,\n    bytes32 domainSalt\n  )\n    internal\n  {\n    uint256 chainId;\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      chainId := chainid()\n    }\n\n    typedDataDomainSeparator = keccak256(abi.encode(\n        TYPED_DATA_DOMAIN_TYPE_HASH,\n        domainNameHash,\n        domainVersionHash,\n        chainId,\n        address(this),\n        domainSalt\n    ));\n  }\n\n  // internal functions (views)\n\n  /**\n   * @notice Hashes primary typed data\n   * @param dataHash hash of the data\n   */\n  function _hashPrimaryTypedData(\n    bytes32 dataHash\n  )\n    internal\n    view\n    returns (bytes32)\n  {\n    return keccak256(abi.encodePacked(\n      TYPED_DATA_PREFIX,\n      typedDataDomainSeparator,\n      dataHash\n    ));\n  }\n}\n"
    },
    "src/gateway/GatewayRecipient.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/BytesLib.sol\";\n\n\n/**\n * @title Gateway recipient\n *\n * @notice Gateway target contract\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract GatewayRecipient {\n  using BytesLib for bytes;\n\n  address public gateway;\n\n  /**\n   * @dev internal constructor\n   */\n  constructor() internal {}\n\n  // internal functions\n\n  /**\n   * @notice Initializes `GatewayRecipient` contract\n   * @param gateway_ `Gateway` contract address\n   */\n  function _initializeGatewayRecipient(\n    address gateway_\n  )\n    internal\n  {\n    gateway = gateway_;\n  }\n\n  // internal functions (views)\n\n  /**\n   * @notice Gets gateway context account\n   * @return context account address\n   */\n  function _getContextAccount()\n    internal\n    view\n    returns (address)\n  {\n    return _getContextAddress(40);\n  }\n\n  /**\n   * @notice Gets gateway context sender\n   * @return context sender address\n   */\n  function _getContextSender()\n    internal\n    view\n    returns (address)\n  {\n    return _getContextAddress(20);\n  }\n\n  /**\n   * @notice Gets gateway context data\n   * @return context data\n   */\n  function _getContextData()\n    internal\n    view\n    returns (bytes calldata)\n  {\n    bytes calldata result;\n\n    if (_isGatewaySender()) {\n      result = msg.data[:msg.data.length - 40];\n    } else {\n      result = msg.data;\n    }\n\n    return result;\n  }\n\n  // private functions (views)\n\n  function _getContextAddress(\n    uint256 offset\n  )\n    private\n    view\n    returns (address)\n  {\n    address result = address(0);\n\n    if (_isGatewaySender()) {\n      uint from = msg.data.length - offset;\n      result = bytes(msg.data[from:from + 20]).toAddress();\n    } else {\n      result = msg.sender;\n    }\n\n    return result;\n  }\n\n  function _isGatewaySender()\n    private\n    view\n    returns (bool)\n  {\n    bool result;\n\n    if (msg.sender == gateway) {\n      require(\n        msg.data.length >= 44,\n        \"GatewayRecipient: invalid msg.data\"\n      );\n\n      result = true;\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/ens/resolvers/ENSAddressResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract address resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/AddrResolver.sol\n */\nabstract contract ENSAddressResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_ADDR_ID = bytes4(keccak256(abi.encodePacked(\"addr(bytes32)\")));\n  bytes4 internal constant INTERFACE_ADDRESS_ID = bytes4(keccak256(abi.encodePacked(\"addr(bytes32,uint)\")));\n\n  uint internal constant COIN_TYPE_ETH = 60;\n\n  mapping(bytes32 => mapping(uint => bytes)) internal resolverAddresses;\n\n  // events\n\n  event AddrChanged(\n    bytes32 indexed node,\n    address addr\n  );\n\n  event AddressChanged(\n    bytes32 indexed node,\n    uint coinType,\n    bytes newAddress\n  );\n\n  // external functions\n\n  function setAddr(\n    bytes32 node,\n    address addr_\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    _setAddr(node, addr_);\n  }\n\n  function setAddr(\n    bytes32 node,\n    uint coinType,\n    bytes memory addr_\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    _setAddr(node, coinType, addr_);\n  }\n\n  // external functions (views)\n\n  function addr(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    return _addr(node);\n  }\n\n  function addr(\n    bytes32 node,\n    uint coinType\n  )\n    external\n    view\n    returns (bytes memory)\n  {\n    return resolverAddresses[node][coinType];\n  }\n\n  // internal functions\n\n  function _setAddr(\n    bytes32 node,\n    address addr_\n  )\n    internal\n  {\n    _setAddr(node, COIN_TYPE_ETH, _addressToBytes(addr_));\n  }\n\n  function _setAddr(\n    bytes32 node,\n    uint coinType,\n    bytes memory addr_\n  )\n    internal\n  {\n    emit AddressChanged(node, coinType, addr_);\n\n    if(coinType == COIN_TYPE_ETH) {\n      emit AddrChanged(node, _bytesToAddress(addr_));\n    }\n\n    resolverAddresses[node][coinType] = addr_;\n  }\n\n  // internal functions (views)\n\n  function _addr(\n    bytes32 node\n  )\n    internal\n    view\n    returns (address)\n  {\n    address result;\n\n    bytes memory addr_ = resolverAddresses[node][COIN_TYPE_ETH];\n\n    if (addr_.length > 0) {\n      result = _bytesToAddress(addr_);\n    }\n\n    return result;\n  }\n\n  // private function (pure)\n\n  function _bytesToAddress(\n    bytes memory data\n  )\n    private\n    pure\n    returns(address payable)\n  {\n    address payable result;\n\n    require(data.length == 20);\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      result := div(mload(add(data, 32)), exp(256, 12))\n    }\n\n    return result;\n  }\n\n  function _addressToBytes(\n    address addr_\n  )\n    private\n    pure\n    returns(bytes memory)\n  {\n    bytes memory result = new bytes(20);\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      mstore(add(result, 32), mul(addr_, exp(256, 12)))\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/ens/resolvers/ENSNameResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract name resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/NameResolver.sol\n */\nabstract contract ENSNameResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_NAME_ID = bytes4(keccak256(abi.encodePacked(\"name(bytes32)\")));\n\n  mapping(bytes32 => string) internal resolverNames;\n\n  // events\n\n  event NameChanged(\n    bytes32 indexed node,\n    string name\n  );\n\n  // external functions\n\n  function setName(\n    bytes32 node,\n    string calldata name\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    resolverNames[node] = name;\n\n    emit NameChanged(node, name);\n  }\n\n  // external functions (views)\n\n  function name(\n    bytes32 node\n  )\n    external\n    view\n    returns (string memory)\n  {\n    return resolverNames[node];\n  }\n}\n"
    },
    "src/ens/resolvers/ENSPubKeyResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract pub key resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/PubkeyResolver.sol\n */\nabstract contract ENSPubKeyResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_PUB_KEY_ID = bytes4(keccak256(abi.encodePacked(\"pubkey(bytes32)\")));\n\n  struct PubKey {\n    bytes32 x;\n    bytes32 y;\n  }\n\n  mapping(bytes32 => PubKey) internal resolverPubKeys;\n\n  // events\n\n  event PubkeyChanged(\n    bytes32 indexed node,\n    bytes32 x,\n    bytes32 y\n  );\n\n  // external functions (views)\n\n  function setPubkey(\n    bytes32 node,\n    bytes32 x,\n    bytes32 y\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    resolverPubKeys[node] = PubKey(x, y);\n\n    emit PubkeyChanged(node, x, y);\n  }\n\n  // external functions (views)\n\n  function pubkey(\n    bytes32 node\n  )\n    external\n    view\n    returns (bytes32 x, bytes32 y)\n  {\n    return (resolverPubKeys[node].x, resolverPubKeys[node].y);\n  }\n}\n"
    },
    "src/ens/resolvers/ENSTextResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract text resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/TextResolver.sol\n */\nabstract contract ENSTextResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_TEXT_ID = bytes4(keccak256(abi.encodePacked(\"text(bytes32,string)\")));\n\n  mapping(bytes32 => mapping(string => string)) internal resolverTexts;\n\n  // events\n\n  event TextChanged(\n    bytes32 indexed node,\n    string indexed indexedKey,\n    string key\n  );\n\n  // external functions (views)\n\n  function setText(\n    bytes32 node,\n    string calldata key,\n    string calldata value\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    resolverTexts[node][key] = value;\n\n    emit TextChanged(node, key, key);\n  }\n\n  // external functions (views)\n\n  function text(\n    bytes32 node,\n    string calldata key\n  )\n    external\n    view\n    returns (string memory)\n  {\n    return resolverTexts[node][key];\n  }\n}\n"
    },
    "src/ens/ENSRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ENS registry\n *\n * @dev Base on https://github.com/ensdomains/ens/blob/ff0f41747c05f1598973b0fe7ad0d9e09565dfcd/contracts/ENSRegistry.sol\n */\ncontract ENSRegistry {\n  struct Record {\n    address owner;\n    address resolver;\n    uint64 ttl;\n  }\n\n  mapping (bytes32 => Record) private records;\n  mapping (address => mapping(address => bool)) private operators;\n\n  // events\n\n  event NewOwner(\n    bytes32 indexed node,\n    bytes32 indexed label,\n    address owner\n  );\n\n  event Transfer(\n    bytes32 indexed node,\n    address owner\n  );\n\n  event NewResolver(\n    bytes32 indexed node,\n    address resolver\n  );\n\n  event NewTTL(\n    bytes32 indexed node,\n    uint64 ttl\n  );\n\n  event ApprovalForAll(\n    address indexed owner,\n    address indexed operator,\n    bool approved\n  );\n\n  // modifiers\n\n  modifier authorised(\n    bytes32 node\n  )\n  {\n    address owner = records[node].owner;\n\n    require(\n      owner == msg.sender || operators[owner][msg.sender],\n      \"ENSRegistry: reverted by authorised modifier\"\n    );\n\n    _;\n  }\n\n  /**\n   * @dev Public constructor\n   */\n  constructor()\n    public\n  {\n    // solhint-disable-next-line avoid-tx-origin\n    records[0x0].owner = tx.origin;\n  }\n\n  // external functions\n\n  function setRecord(\n    bytes32 node,\n    address owner_,\n    address resolver_,\n    uint64 ttl_\n  )\n    external\n  {\n    setOwner(node, owner_);\n\n    _setResolverAndTTL(node, resolver_, ttl_);\n  }\n\n  function setTTL(\n    bytes32 node,\n    uint64 ttl_\n  )\n    external\n    authorised(node)\n  {\n    records[node].ttl = ttl_;\n\n    emit NewTTL(node, ttl_);\n  }\n\n  function setSubnodeRecord(\n    bytes32 node,\n    bytes32 label,\n    address owner_,\n    address resolver_,\n    uint64 ttl_\n  )\n    external\n  {\n    bytes32 subNode = setSubnodeOwner(node, label, owner_);\n\n    _setResolverAndTTL(subNode, resolver_, ttl_);\n  }\n\n  function setApprovalForAll(\n    address operator,\n    bool approved\n  )\n    external\n  {\n    operators[msg.sender][operator] = approved;\n\n    emit ApprovalForAll(\n      msg.sender,\n      operator,\n      approved\n    );\n  }\n\n  // external functions (views)\n\n  function owner(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    address addr = records[node].owner;\n\n    if (addr == address(this)) {\n      return address(0x0);\n    }\n\n    return addr;\n  }\n\n  function resolver(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    return records[node].resolver;\n  }\n\n  function ttl(\n    bytes32 node\n  )\n    external\n    view\n    returns (uint64)\n  {\n    return records[node].ttl;\n  }\n\n  function recordExists(\n    bytes32 node\n  )\n    external\n    view\n    returns (bool)\n  {\n    return records[node].owner != address(0x0);\n  }\n\n  function isApprovedForAll(\n    address owner_,\n    address operator\n  )\n    external\n    view\n    returns (bool)\n  {\n    return operators[owner_][operator];\n  }\n\n  // public functions\n\n  function setOwner(\n    bytes32 node,\n    address owner_\n  )\n    public\n    authorised(node)\n  {\n    records[node].owner = owner_;\n\n    emit Transfer(node, owner_);\n  }\n\n  function setResolver(\n    bytes32 node,\n    address resolver_\n  )\n    public\n    authorised(node)\n  {\n    records[node].resolver = resolver_;\n\n    emit NewResolver(node, resolver_);\n  }\n\n  function setSubnodeOwner(\n    bytes32 node,\n    bytes32 label,\n    address owner_\n  )\n    public\n    authorised(node)\n    returns(bytes32)\n  {\n    bytes32 subNode = keccak256(abi.encodePacked(node, label));\n\n    records[subNode].owner = owner_;\n\n    emit NewOwner(node, label, owner_);\n\n    return subNode;\n  }\n\n  // private functions\n\n  function _setResolverAndTTL(\n    bytes32 node,\n    address resolver_,\n    uint64 ttl_\n  )\n    private\n  {\n    if (resolver_ != records[node].resolver) {\n      records[node].resolver = resolver_;\n\n      emit NewResolver(node, resolver_);\n    }\n\n    if (ttl_ != records[node].ttl) {\n      records[node].ttl = ttl_;\n\n      emit NewTTL(node, ttl_);\n    }\n  }\n}\n"
    },
    "src/common/libs/SignatureLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Signature library\n *\n * @dev Based on\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/cryptography/ECDSA.sol#L26\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/utils/Strings.sol#L12\n */\nlibrary SignatureLib {\n  function recoverAddress(\n    bytes32 messageHash,\n    bytes memory signature\n  )\n    internal\n    pure\n    returns (address)\n  {\n    address result = address(0);\n\n    if (signature.length == 65) {\n      bytes32 r;\n      bytes32 s;\n      uint8 v;\n\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        r := mload(add(signature, 0x20))\n        s := mload(add(signature, 0x40))\n        v := byte(0, mload(add(signature, 0x60)))\n      }\n\n      if (v < 27) {\n        v += 27;\n      }\n\n      if (v == 27 || v == 28) {\n        result = ecrecover(messageHash, v, r, s);\n      }\n    }\n\n    return result;\n  }\n\n  function toEthereumSignedMessageHash(\n    bytes memory message\n  )\n    internal\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encodePacked(\n      \"\\x19Ethereum Signed Message:\\n\",\n      _uintToString(message.length),\n      abi.encodePacked(message)\n    ));\n  }\n\n  function _uintToString(\n    uint num\n  )\n    private\n    pure\n    returns (string memory)\n  {\n    if (num == 0) {\n      return \"0\";\n    } else if (num == 32) {\n      return \"32\";\n    }\n\n    uint i = num;\n    uint j = num;\n\n    uint len;\n\n    while (j != 0) {\n      len++;\n      j /= 10;\n    }\n\n    bytes memory result = new bytes(len);\n\n    uint k = len - 1;\n\n    while (i != 0) {\n      result[k--] = byte(uint8(48 + i % 10));\n      i /= 10;\n    }\n\n    return string(result);\n  }\n}\n"
    },
    "src/common/libs/BytesLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Bytes library\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\nlibrary BytesLib {\n  /**\n   * @notice Converts bytes to address\n   * @param data data\n   * @return address\n   */\n  function toAddress(\n    bytes memory data\n  )\n    internal\n    pure\n    returns (address)\n  {\n    address result;\n\n    require(\n      data.length == 20,\n      \"BytesLib: invalid data length\"\n    );\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      result := div(mload(add(data, 0x20)), 0x1000000000000000000000000)\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/ens/resolvers/ENSAbstractResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ENS abstract resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/ResolverBase.sol\n */\nabstract contract ENSAbstractResolver {\n  // modifiers\n\n  modifier onlyNodeOwner(bytes32 node)\n  {\n    require(\n      _isNodeOwner(node),\n      \"ENSAbstractResolver: reverted by onlyNodeOwner modifier\"\n    );\n\n    _;\n  }\n\n  // internal functions (views)\n\n  function _isNodeOwner(\n    bytes32 node\n  )\n    internal\n    virtual\n    view\n    returns (bool);\n}\n"
    },
    "src/ens/ENSReverseRegistrar.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/AddressLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n/**\n * @title ENS reverse registrar\n *\n * @dev Base on https://github.com/ensdomains/ens/blob/ff0f41747c05f1598973b0fe7ad0d9e09565dfcd/contracts/ReverseRegistrar.sol\n */\ncontract ENSReverseRegistrar is Initializable {\n  using AddressLib for address;\n\n  // namehash('addr.reverse')\n  bytes32 public constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;\n\n  ENSRegistry public registry;\n  ENSNameResolver public resolver;\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `ENSReverseRegistrar` contract\n   * @param registry_ ENS registry address\n   * @param resolver_ ENS name resolver address\n   */\n  function initialize(\n    ENSRegistry registry_,\n    ENSNameResolver resolver_\n  )\n    external\n    onlyInitializer\n  {\n    registry = registry_;\n    resolver = resolver_;\n  }\n\n  // external functions\n\n  function claim(\n    address owner\n  )\n    public\n    returns (bytes32)\n  {\n    return _claimWithResolver(owner, address(0));\n  }\n\n  function claimWithResolver(\n    address owner,\n    address resolver_\n  )\n    public\n    returns (bytes32)\n  {\n    return _claimWithResolver(owner, resolver_);\n  }\n\n  function setName(\n    string memory name\n  )\n    public\n    returns (bytes32)\n  {\n    bytes32 node = _claimWithResolver(address(this), address(resolver));\n\n    resolver.setName(node, name);\n\n    return node;\n  }\n\n  // external functions (pure)\n\n  function node(\n    address addr_\n  )\n    external\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encodePacked(ADDR_REVERSE_NODE, addr_.toSha3Hash()));\n  }\n\n  // private functions\n\n  function _claimWithResolver(\n    address owner,\n    address resolver_\n  )\n    private\n    returns (bytes32)\n  {\n    bytes32 label = address(msg.sender).toSha3Hash();\n    bytes32 node_ = keccak256(abi.encodePacked(ADDR_REVERSE_NODE, label));\n    address currentOwner = registry.owner(node_);\n\n    if (resolver_ != address(0x0) && resolver_ != registry.resolver(node_)) {\n      if (currentOwner != address(this)) {\n        registry.setSubnodeOwner(ADDR_REVERSE_NODE, label, address(this));\n        currentOwner = address(this);\n      }\n\n      registry.setResolver(node_, resolver_);\n    }\n\n    // Update the owner if required\n    if (currentOwner != owner) {\n      registry.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);\n    }\n\n    return node_;\n  }\n}\n"
    },
    "src/common/libs/AddressLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Address library\n */\nlibrary AddressLib {\n  /**\n   * @notice Converts address into sha3 hash\n   * @param self address\n   * @return sha3 hash\n   */\n  function toSha3Hash(\n    address self\n  )\n    internal\n    pure\n    returns (bytes32)\n  {\n    bytes32 result;\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      let lookup := 0x3031323334353637383961626364656600000000000000000000000000000000\n\n      for { let i := 40 } gt(i, 0) { } {\n        i := sub(i, 1)\n        mstore8(i, byte(and(self, 0xf), lookup))\n        self := div(self, 0x10)\n        i := sub(i, 1)\n        mstore8(i, byte(and(self, 0xf), lookup))\n        self := div(self, 0x10)\n      }\n\n      result := keccak256(0, 40)\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/ens/ENSHelper.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"./resolvers/ENSAddressResolver.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n/**\n * @title ENS helper\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract ENSHelper is Initializable {\n  ENSRegistry public registry;\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `ENSLookupHelper` contract\n   * @param registry_ ENS registry address\n   */\n  function initialize(\n    ENSRegistry registry_\n  )\n    external\n    onlyInitializer\n  {\n    registry = registry_;\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Gets nodes addresses\n   * @param nodes array of nodes\n   * @return nodes addresses\n   */\n  function getAddresses(\n    bytes32[] memory nodes\n  )\n    external\n    view\n    returns (address[] memory)\n  {\n    uint nodesLen = nodes.length;\n    address[] memory result = new address[](nodesLen);\n\n    for (uint i = 0; i < nodesLen; i++) {\n      result[i] = _getAddress(nodes[i]);\n    }\n\n    return result;\n  }\n\n  /**\n   * @notice Gets nodes names\n   * @param nodes array of nodes\n   * @return nodes names\n   */\n  function getNames(\n    bytes32[] memory nodes\n  )\n    external\n    view\n    returns (string[] memory)\n  {\n    uint nodesLen = nodes.length;\n    string[] memory result = new string[](nodesLen);\n\n    for (uint i = 0; i < nodesLen; i++) {\n      result[i] = _getName(nodes[i]);\n    }\n\n    return result;\n  }\n\n  // private functions (views)\n\n  function _getAddress(\n    bytes32 node\n  )\n    private\n    view\n    returns (address)\n  {\n    address result;\n    address resolver = registry.resolver(node);\n\n    if (resolver != address(0)) {\n      try ENSAddressResolver(resolver).addr(node) returns (address addr) {\n        result = addr;\n      } catch {\n        //\n      }\n    }\n\n    return result;\n  }\n\n  function _getName(\n    bytes32 node\n  )\n    private\n    view\n    returns (string memory)\n  {\n    string memory result;\n    address resolver = registry.resolver(node);\n\n    if (resolver != address(0)) {\n      try ENSNameResolver(resolver).name(node) returns (string memory name) {\n        result = name;\n      } catch {\n        //\n      }\n    }\n\n    return result;\n  }\n}\n"
    }
  },
  "settings": {
    "evmVersion": "istanbul",
    "metadata": {
      "bytecodeHash": "none",
      "useLiteralContent": true
    },
    "optimizer": {
      "enabled": false,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates"
        ],
        "": [
          "ast"
        ]
      }
    }
  }
}