{
  "language": "Solidity",
  "sources": {
    "src/common/access/Controlled.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Controlled\n *\n * @dev Contract module which provides an access control mechanism.\n * It ensures there is only one controlling account of the smart contract\n * and grants that account exclusive access to specific functions.\n *\n * The controller account will be the one that deploys the contract.\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Controlled {\n  /**\n   * @return controller account address\n   */\n  address public controller;\n\n  // modifiers\n\n  /**\n   * @dev Throws if msg.sender is not the controller\n   */\n  modifier onlyController() {\n    require(\n      msg.sender == controller,\n      \"Controlled: msg.sender is not the controller\"\n    );\n\n    _;\n  }\n\n  /**\n   * @dev Internal constructor\n   */\n  constructor()\n    internal\n  {\n    controller = msg.sender;\n  }\n}\n"
    },
    "src/payments/PaymentDepositAccount.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/access/Controlled.sol\";\n\n\n/**\n * @title Payment deposit account\n *\n * @dev Simple account contract with only one method - `executeTransaction`\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract PaymentDepositAccount is Controlled {\n  /**\n   * @dev Public constructor\n   */\n  constructor() public payable Controlled() {}\n\n  /**\n   * @notice Allow receives\n   */\n  receive()\n    external\n    payable\n  {\n    //\n  }\n\n  // external functions\n\n  /**\n   * @notice Executes transaction\n   * @param to to address\n   * @param value value\n   * @param data data\n   * @return transaction result\n   */\n  function executeTransaction(\n    address to,\n    uint256 value,\n    bytes calldata data\n  )\n    external\n    onlyController\n    returns (bytes memory)\n  {\n    bytes memory result;\n    bool succeeded;\n\n    // solhint-disable-next-line avoid-call-value, avoid-low-level-calls\n    (succeeded, result) = payable(to).call{value: value}(data);\n\n    require(\n      succeeded,\n      \"Account: transaction reverted\"\n    );\n\n    return result;\n  }\n}\n"
    },
    "src/payments/PaymentRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/access/Guarded.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/libs/SignatureLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/token/ERC20Token.sol\";\nimport \"../common/typedData/TypedDataContainer.sol\";\nimport \"../external/ExternalAccountRegistry.sol\";\nimport \"../personal/PersonalAccountRegistry.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\nimport \"./PaymentDepositAccount.sol\";\n\n\n/**\n * @title Payment registry\n *\n * @notice A registry for payment and payment channels\n *\n * @dev the `DepositExit` process can be used in a case operator (guardian) couldn't sign commit / withdrawal message.\n * Process will be rejected when any of senders channels will be committed.\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract PaymentRegistry is Guarded, Initializable, TypedDataContainer, GatewayRecipient {\n  using SafeMathLib for uint256;\n  using SignatureLib for bytes32;\n\n  struct Deposit {\n    address account;\n    mapping(address => uint256) withdrawnAmount;\n    mapping(address => uint256) exitLockedUntil;\n  }\n\n  struct PaymentChannel {\n    uint256 committedAmount;\n  }\n\n  struct DepositWithdrawal {\n    address owner;\n    address token;\n    uint256 amount;\n  }\n\n  struct PaymentChannelCommit {\n    address sender;\n    address recipient;\n    address token;\n    bytes32 uid;\n    uint256 blockNumber;\n    uint256 amount;\n  }\n\n  uint256 private constant DEFAULT_DEPOSIT_EXIT_LOCK_PERIOD = 28 days;\n  bytes32 private constant DEPOSIT_WITHDRAWAL_TYPE_HASH = keccak256(\n    \"DepositWithdrawal(address owner,address token,uint256 amount)\"\n  );\n  bytes32 private constant PAYMENT_CHANNEL_COMMIT_TYPE_HASH = keccak256(\n    \"PaymentChannelCommit(address sender,address recipient,address token,bytes32 uid,uint256 blockNumber,uint256 amount)\"\n  );\n\n  ExternalAccountRegistry public externalAccountRegistry;\n  PersonalAccountRegistry public personalAccountRegistry;\n\n  uint256 public depositExitLockPeriod;\n\n  mapping(address => Deposit) private deposits;\n  mapping(bytes32 => PaymentChannel) private paymentChannels;\n\n  // events\n\n  /**\n   * @dev Emitted when the deposit account is deployed\n   * @param depositAccount deposit account address\n   * @param owner owner address\n   */\n  event DepositAccountDeployed(\n    address depositAccount,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when the deposit exist is requested\n   * @param depositAccount deposit account address\n   * @param owner owner address\n   * @param token token address\n   * @param lockedUntil deposit exist locked util time\n   */\n  event DepositExitRequested(\n    address depositAccount,\n    address owner,\n    address token,\n    uint256 lockedUntil\n  );\n\n  /**\n   * @dev Emitted when the deposit exist is completed\n   * @param depositAccount deposit account address\n   * @param owner owner address\n   * @param token token address\n   * @param amount deposit exist amount\n   */\n  event DepositExitCompleted(\n    address depositAccount,\n    address owner,\n    address token,\n    uint256 amount\n  );\n\n  /**\n   * @dev Emitted when the deposit exist is rejected\n   * @param depositAccount deposit account address\n   * @param owner owner address\n   * @param token token address\n   */\n  event DepositExitRejected(\n    address depositAccount,\n    address owner,\n    address token\n  );\n\n  /**\n   * @dev Emitted when the deposit has been withdrawn\n   * @param depositAccount deposit account address\n   * @param owner owner address\n   * @param token token address\n   * @param amount withdrawn amount\n   */\n  event DepositWithdrawn(\n    address depositAccount,\n    address owner,\n    address token,\n    uint256 amount\n  );\n\n  /**\n   * @dev Emitted when the payment channel has been committed\n   * @param hash channel hash\n   * @param sender sender address\n   * @param recipient recipient address\n   * @param token token address\n   * @param uid unique channel id\n   * @param amount committed amount\n   */\n  event PaymentChannelCommitted(\n    bytes32 hash,\n    address sender,\n    address recipient,\n    address token,\n    bytes32 uid,\n    uint256 amount\n  );\n\n  /**\n   * @dev Emitted when the payment has been withdrawn\n   * @param channelHash channel hash\n   * @param value payment value\n   */\n  event PaymentWithdrawn(\n    bytes32 channelHash,\n    uint256 value\n  );\n\n  /**\n   * @dev Emitted when the payment has been deposited\n   * @param channelHash channel hash\n   * @param value payment value\n   */\n  event PaymentDeposited(\n    bytes32 channelHash,\n    uint256 value\n  );\n\n  /**\n   * @dev Emitted when the payment has been withdrawn and deposited (split)\n   * @param channelHash channel hash\n   * @param totalValue payment total value\n   * @param depositValue payment deposited value\n   */\n  event PaymentSplit(\n    bytes32 channelHash,\n    uint256 totalValue,\n    uint256 depositValue\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Guarded() Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initialize `PaymentRegistry` contract\n   * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\n   * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\n   * @param depositExitLockPeriod_ deposit exit lock period\n   * @param guardians_ array of guardians addresses\n   * @param gateway_ `Gateway` contract 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    ExternalAccountRegistry externalAccountRegistry_,\n    PersonalAccountRegistry personalAccountRegistry_,\n    uint256 depositExitLockPeriod_,\n    address[] calldata guardians_,\n    address gateway_,\n    bytes32 typedDataDomainNameHash,\n    bytes32 typedDataDomainVersionHash,\n    bytes32 typedDataDomainSalt\n  )\n    external\n    onlyInitializer\n  {\n    externalAccountRegistry = externalAccountRegistry_;\n    personalAccountRegistry = personalAccountRegistry_;\n\n    if (depositExitLockPeriod_ == 0) {\n      depositExitLockPeriod = DEFAULT_DEPOSIT_EXIT_LOCK_PERIOD;\n    } else {\n      depositExitLockPeriod = depositExitLockPeriod_;\n    }\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 Deploys deposit account\n   * @param owner owner address\n   */\n  function deployDepositAccount(\n    address owner\n  )\n    external\n  {\n    _deployDepositAccount(owner);\n  }\n\n  /**\n   * @notice Requests deposit exit\n   * @param token token address\n   */\n  function requestDepositExit(\n    address token\n  )\n    external\n  {\n    address owner = _getContextAccount();\n    uint256 lockedUntil = deposits[owner].exitLockedUntil[token];\n\n    require(\n      lockedUntil == 0,\n      \"PaymentRegistry: deposit exit already requested\"\n    );\n\n    _deployDepositAccount(owner);\n\n    // solhint-disable-next-line not-rely-on-time\n    lockedUntil = now.add(depositExitLockPeriod);\n\n    deposits[owner].exitLockedUntil[token] = lockedUntil;\n\n    emit DepositExitRequested(\n      deposits[owner].account,\n      owner,\n      token,\n      lockedUntil\n    );\n  }\n\n  /**\n   * @notice Processes deposit exit\n   * @param token token address\n   */\n  function processDepositExit(\n    address token\n  )\n    external\n  {\n    address owner = _getContextAccount();\n    uint256 lockedUntil = deposits[owner].exitLockedUntil[token];\n\n    require(\n      lockedUntil != 0,\n      \"PaymentRegistry: deposit exit not requested\"\n    );\n\n    require(\n      // solhint-disable-next-line not-rely-on-time\n      lockedUntil <= now,\n      \"PaymentRegistry: deposit exit locked\"\n    );\n\n    deposits[owner].exitLockedUntil[token] = 0;\n\n    address depositAccount = deposits[owner].account;\n    uint256 depositValue;\n\n    if (token == address(0)) {\n      depositValue = depositAccount.balance;\n    } else {\n      depositValue = ERC20Token(token).balanceOf(depositAccount);\n    }\n\n    _transferFromDeposit(\n      depositAccount,\n      owner,\n      token,\n      depositValue\n    );\n\n    emit DepositExitCompleted(\n      depositAccount,\n      owner,\n      token,\n      depositValue\n    );\n  }\n\n  /**\n   * @notice Withdraws deposit\n   * @param token token address\n   * @param amount amount to withdraw\n   * @param guardianSignature guardian signature\n   */\n  function withdrawDeposit(\n    address token,\n    uint256 amount,\n    bytes calldata guardianSignature\n  )\n    external\n  {\n    address owner = _getContextAccount();\n    uint256 value = amount.sub(deposits[owner].withdrawnAmount[token]);\n\n    require(\n      value > 0,\n      \"PaymentRegistry: invalid amount\"\n    );\n\n    bytes32 messageHash = _hashPrimaryTypedData(\n      _hashTypedData(\n        owner,\n        token,\n        amount\n      )\n    );\n\n    require(\n      _verifyGuardianSignature(messageHash, guardianSignature),\n      \"PaymentRegistry: invalid guardian signature\"\n    );\n\n    deposits[owner].withdrawnAmount[token] = amount;\n\n    _verifyDepositExitOrDeployAccount(owner, token);\n\n    _transferFromDeposit(\n      deposits[owner].account,\n      owner,\n      token,\n      value\n    );\n\n    emit DepositWithdrawn(\n      deposits[owner].account,\n      owner,\n      token,\n      amount\n    );\n  }\n\n  /**\n   * @notice Commits payment channel and withdraw payment\n   * @param sender sender address\n   * @param token token address\n   * @param uid unique channel id\n   * @param blockNumber block number\n   * @param amount amount to commit\n   * @param senderSignature sender signature\n   * @param guardianSignature guardian signature\n   */\n  function commitPaymentChannelAndWithdraw(\n    address sender,\n    address token,\n    bytes32 uid,\n    uint256 blockNumber,\n    uint256 amount,\n    bytes calldata senderSignature,\n    bytes calldata guardianSignature\n  )\n    external\n  {\n    address recipient = _getContextAccount();\n\n    (bytes32 hash, address depositAccount, uint256 paymentValue) = _commitPaymentChannel(\n      sender,\n      recipient,\n      token,\n      uid,\n      blockNumber,\n      amount,\n      senderSignature,\n      guardianSignature\n    );\n\n    _transferFromDeposit(\n      depositAccount,\n      recipient,\n      token,\n      paymentValue\n    );\n\n    emit PaymentWithdrawn(hash, paymentValue);\n  }\n\n  /**\n   * @notice Commits payment channel and deposit payment\n   * @param sender sender address\n   * @param token token address\n   * @param uid unique channel id\n   * @param blockNumber block number\n   * @param amount amount to commit\n   * @param senderSignature sender signature\n   * @param guardianSignature guardian signature\n   */\n  function commitPaymentChannelAndDeposit(\n    address sender,\n    address token,\n    bytes32 uid,\n    uint256 blockNumber,\n    uint256 amount,\n    bytes calldata senderSignature,\n    bytes calldata guardianSignature\n  )\n    external\n  {\n    address recipient = _getContextAccount();\n\n    (bytes32 hash, address depositAccount, uint256 paymentValue) = _commitPaymentChannel(\n      sender,\n      recipient,\n      token,\n      uid,\n      blockNumber,\n      amount,\n      senderSignature,\n      guardianSignature\n    );\n\n    _transferFromDeposit(\n      depositAccount,\n      _computeDepositAccountAddress(recipient),\n      token,\n      paymentValue\n    );\n\n    emit PaymentDeposited(hash, paymentValue);\n  }\n\n  /**\n   * @notice Commits payment channel, withdraws and deposits (split) payment\n   * @param sender sender address\n   * @param token token address\n   * @param uid unique channel id\n   * @param blockNumber block number\n   * @param amount amount to commit\n   * @param depositPaymentValue amount to deposit\n   * @param senderSignature sender signature\n   * @param guardianSignature guardian signature\n   */\n  function commitPaymentChannelAndSplit(\n    address sender,\n    address token,\n    bytes32 uid,\n    uint256 blockNumber,\n    uint256 amount,\n    uint256 depositPaymentValue,\n    bytes calldata senderSignature,\n    bytes calldata guardianSignature\n  )\n    external\n  {\n    address recipient = _getContextAccount();\n\n    (bytes32 hash, address depositAccount, uint256 paymentValue) = _commitPaymentChannel(\n      sender,\n      recipient,\n      token,\n      uid,\n      blockNumber,\n      amount,\n      senderSignature,\n      guardianSignature\n    );\n\n    _transferSplitFromDeposit(\n      depositAccount,\n      recipient,\n      token,\n      paymentValue,\n      depositPaymentValue\n    );\n\n    emit PaymentSplit(hash, paymentValue, depositPaymentValue);\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Computes deposit account address\n   * @param owner owner address\n   * @return deposit account address\n   */\n  function computeDepositAccountAddress(\n    address owner\n  )\n    external\n    view\n    returns (address)\n  {\n    return _computeDepositAccountAddress(owner);\n  }\n\n  /**\n   * @notice Checks if deposit account is deployed\n   * @param owner owner address\n   * @return true when deposit account is deployed\n   */\n  function isDepositAccountDeployed(\n    address owner\n  )\n    external\n    view\n    returns (bool)\n  {\n    return deposits[owner].account != address(0);\n  }\n\n  /**\n   * @notice Gets deposit exit locked until time\n   * @param owner owner address\n   * @param token token address\n   * @return locked until time\n   */\n  function getDepositExitLockedUntil(\n    address owner,\n    address token\n  )\n    external\n    view\n    returns (uint256)\n  {\n    return deposits[owner].exitLockedUntil[token];\n  }\n\n  /**\n   * @notice Gets deposit withdrawn amount\n   * @param owner owner address\n   * @param token token address\n   * @return withdrawn amount\n   */\n  function getDepositWithdrawnAmount(\n    address owner,\n    address token\n  )\n    external\n    view\n    returns (uint256)\n  {\n    return deposits[owner].withdrawnAmount[token];\n  }\n\n  /**\n   * @notice Gets payment channel committed amount\n   * @param hash payment channel hash\n   * @return committed amount\n   */\n  function getPaymentChannelCommittedAmount(\n    bytes32 hash\n  )\n    external\n    view\n    returns (uint256)\n  {\n    return paymentChannels[hash].committedAmount;\n  }\n\n  // external functions (pure)\n\n  /**\n   * @notice Computes payment channel hash\n   * @param sender sender address\n   * @param recipient recipient address\n   * @param token token address\n   * @param uid unique channel id\n   * @return hash\n   */\n  function computePaymentChannelHash(\n    address sender,\n    address recipient,\n    address token,\n    bytes32 uid\n  )\n    external\n    pure\n    returns (bytes32)\n  {\n    return _computePaymentChannelHash(\n      sender,\n      recipient,\n      token,\n      uid\n    );\n  }\n\n  // public functions (views)\n\n  /**\n   * @notice Hashes `DepositWithdrawal` typed data\n   * @param depositWithdrawal struct\n   * @return hash\n   */\n  function hashDepositWithdrawal(\n    DepositWithdrawal memory depositWithdrawal\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashPrimaryTypedData(\n      _hashTypedData(\n        depositWithdrawal.owner,\n        depositWithdrawal.token,\n        depositWithdrawal.amount\n      )\n    );\n  }\n\n  /**\n   * @notice Hashes `PaymentChannelCommit` typed data\n   * @param paymentChannelCommit struct\n   * @return hash\n   */\n  function hashPaymentChannelCommit(\n    PaymentChannelCommit memory paymentChannelCommit\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashPrimaryTypedData(\n      _hashTypedData(\n        paymentChannelCommit.sender,\n        paymentChannelCommit.recipient,\n        paymentChannelCommit.token,\n        paymentChannelCommit.uid,\n        paymentChannelCommit.blockNumber,\n        paymentChannelCommit.amount\n      )\n    );\n  }\n\n  // private functions\n\n  function _deployDepositAccount(\n    address owner\n  )\n    private\n  {\n    if (deposits[owner].account == address(0)) {\n      bytes32 salt = keccak256(\n        abi.encodePacked(\n          owner\n        )\n      );\n\n      deposits[owner].account = address(new PaymentDepositAccount{salt: salt}());\n\n      emit DepositAccountDeployed(\n        deposits[owner].account,\n        owner\n      );\n    }\n  }\n\n  function _verifyDepositExitOrDeployAccount(\n    address owner,\n    address token\n  )\n    private\n  {\n    if (deposits[owner].exitLockedUntil[token] > 0) {\n      deposits[owner].exitLockedUntil[token] = 0;\n\n      emit DepositExitRejected(\n        deposits[owner].account,\n        owner,\n        token\n      );\n    } else {\n      _deployDepositAccount(owner);\n    }\n  }\n\n  function _commitPaymentChannel(\n    address sender,\n    address recipient,\n    address token,\n    bytes32 uid,\n    uint256 blockNumber,\n    uint256 amount,\n    bytes memory senderSignature,\n    bytes memory guardianSignature\n  )\n    private\n    returns (bytes32 hash, address depositAccount, uint256 paymentValue)\n  {\n    bytes32 messageHash = _hashPrimaryTypedData(\n      _hashTypedData(\n        sender,\n        recipient,\n        token,\n        uid,\n        blockNumber,\n        amount\n      )\n    );\n\n    if (senderSignature.length == 0) {\n      require(\n        externalAccountRegistry.verifyAccountProofAtBlock(sender, messageHash, blockNumber),\n        \"PaymentRegistry: invalid guardian signature\"\n      );\n    } else {\n      address signer = messageHash.recoverAddress(senderSignature);\n\n      if (sender != signer) {\n        require(\n          personalAccountRegistry.verifyAccountOwnerAtBlock(sender, signer, blockNumber) ||\n          externalAccountRegistry.verifyAccountOwnerAtBlock(sender, signer, blockNumber),\n          \"PaymentRegistry: invalid sender signature\"\n        );\n      }\n    }\n\n    require(\n      _verifyGuardianSignature(messageHash, guardianSignature),\n      \"PaymentRegistry: invalid guardian signature\"\n    );\n\n    hash = _computePaymentChannelHash(\n      sender,\n      recipient,\n      token,\n      uid\n    );\n\n    /// @dev calc payment value\n    paymentValue = amount.sub(paymentChannels[hash].committedAmount);\n\n    require(\n      paymentValue != 0,\n      \"PaymentRegistry: invalid payment value\"\n    );\n\n    paymentChannels[hash].committedAmount = amount;\n\n    _verifyDepositExitOrDeployAccount(sender, token);\n\n    depositAccount = deposits[sender].account;\n\n    emit PaymentChannelCommitted(\n      hash,\n      sender,\n      recipient,\n      token,\n      uid,\n      amount\n    );\n\n    return (hash, depositAccount, paymentValue);\n  }\n\n  function _transferFromDeposit(\n    address depositAccount,\n    address to,\n    address token,\n    uint256 value\n  )\n    private\n  {\n    if (token == address(0)) {\n      PaymentDepositAccount(payable(depositAccount)).executeTransaction(\n        to,\n        value,\n        new bytes(0)\n      );\n    } else {\n      bytes memory response = PaymentDepositAccount(payable(depositAccount)).executeTransaction(\n        token,\n        0,\n        abi.encodeWithSelector(\n          ERC20Token(token).transfer.selector,\n          to,\n          value\n        )\n      );\n\n      if (response.length > 0) {\n        require(\n          abi.decode(response, (bool)),\n          \"PaymentRegistry: ERC20Token transfer reverted\"\n        );\n      }\n    }\n  }\n\n  function _transferSplitFromDeposit(\n    address depositAccount,\n    address to,\n    address token,\n    uint256 paymentValue,\n    uint256 depositValue\n  )\n    private\n  {\n    require(\n      depositValue > 0,\n      \"PaymentRegistry: invalid deposit value\"\n    );\n\n    uint256 withdrawValue = paymentValue.sub(depositValue);\n\n    require(\n      withdrawValue > 0,\n      \"PaymentRegistry: invalid withdraw value\"\n    );\n\n    _transferFromDeposit(\n      depositAccount,\n      to,\n      token,\n      withdrawValue\n    );\n\n    _transferFromDeposit(\n      depositAccount,\n      _computeDepositAccountAddress(to),\n      token,\n      depositValue\n    );\n  }\n\n  // private functions (views)\n\n  function _computeDepositAccountAddress(\n    address owner\n  )\n    private\n    view\n    returns (address)\n  {\n    bytes32 salt = keccak256(\n      abi.encodePacked(\n        owner\n      )\n    );\n\n    bytes memory creationCode = type(PaymentDepositAccount).creationCode;\n\n    bytes32 data = keccak256(\n      abi.encodePacked(\n        bytes1(0xff),\n        address(this),\n        salt,\n        keccak256(creationCode)\n      )\n    );\n\n    return address(uint160(uint256(data)));\n  }\n\n  // private functions (pure)\n\n  function _computePaymentChannelHash(\n    address sender,\n    address recipient,\n    address token,\n    bytes32 uid\n  )\n    private\n    pure\n    returns (bytes32)\n  {\n    return keccak256(\n      abi.encodePacked(\n        sender,\n        recipient,\n        token,\n        uid\n      )\n    );\n  }\n\n  function _hashTypedData(\n    address owner,\n    address token,\n    uint256 amount\n  )\n    private\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encode(\n      DEPOSIT_WITHDRAWAL_TYPE_HASH,\n      owner,\n      token,\n      amount\n    ));\n  }\n\n  function _hashTypedData(\n    address sender,\n    address recipient,\n    address token,\n    bytes32 uid,\n    uint256 blockNumber,\n    uint256 amount\n  )\n    private\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encode(\n        PAYMENT_CHANNEL_COMMIT_TYPE_HASH,\n        sender,\n        recipient,\n        token,\n        uid,\n        blockNumber,\n        amount\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/libs/SafeMathLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Safe math library\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/math/SafeMath.sol\n */\nlibrary SafeMathLib {\n  function add(uint256 a, uint256 b) internal pure returns (uint256) {\n    uint256 c = a + b;\n\n    require(c >= a, \"SafeMathLib: addition overflow\");\n\n    return c;\n  }\n\n  function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n    return sub(a, b, \"SafeMathLib: subtraction overflow\");\n  }\n\n  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n    require(b <= a, errorMessage);\n\n    return a - b;\n  }\n\n  function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n    if (a == 0) {\n      return 0;\n    }\n\n    uint256 c = a * b;\n\n    require(c / a == b, \"SafeMathLib: multiplication overflow\");\n\n    return c;\n  }\n\n  function div(uint256 a, uint256 b) internal pure returns (uint256) {\n    return div(a, b, \"SafeMathLib: division by zero\");\n  }\n\n  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n    require(b > 0, errorMessage);\n\n    return a / b;\n  }\n\n  function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n    return mod(a, b, \"SafeMathLib: modulo by zero\");\n  }\n\n  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n    require(b != 0, errorMessage);\n\n    return a % b;\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/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/token/ERC20Token.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/SafeMathLib.sol\";\n\n\n/**\n * @title ERC20 token\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/token/ERC20/ERC20.sol\n */\ncontract ERC20Token {\n  using SafeMathLib for uint256;\n\n  string public name;\n  string public symbol;\n  uint8 public decimals;\n  uint256 public totalSupply;\n\n  mapping(address => uint256) internal balances;\n  mapping(address => mapping(address => uint256)) internal allowances;\n\n  // events\n\n  event Transfer(\n    address indexed from,\n    address indexed to,\n    uint256 value\n  );\n\n  event Approval(\n    address indexed owner,\n    address indexed spender,\n    uint256 value\n  );\n\n  /**\n   * @dev internal constructor\n   */\n  constructor() internal {}\n\n  // external functions\n\n  function transfer(\n    address to,\n    uint256 value\n  )\n    external\n    returns (bool)\n  {\n    _transfer(_getSender(), to, value);\n\n    return true;\n  }\n\n  function transferFrom(\n    address from,\n    address to,\n    uint256 value\n  )\n    virtual\n    external\n    returns (bool)\n  {\n    address sender = _getSender();\n\n    _transfer(from, to, value);\n    _approve(from, sender, allowances[from][sender].sub(value));\n\n    return true;\n  }\n\n  function approve(\n    address spender,\n    uint256 value\n  )\n    virtual\n    external\n    returns (bool)\n  {\n    _approve(_getSender(), spender, value);\n\n    return true;\n  }\n\n  // external functions (views)\n\n  function balanceOf(\n    address owner\n  )\n    virtual\n    external\n    view\n    returns (uint256)\n  {\n    return balances[owner];\n  }\n\n  function allowance(\n    address owner,\n    address spender\n  )\n    virtual\n    external\n    view\n    returns (uint256)\n  {\n    return allowances[owner][spender];\n  }\n\n  // internal functions\n\n  function _transfer(\n    address from,\n    address to,\n    uint256 value\n  )\n    virtual\n    internal\n  {\n    require(\n      from != address(0),\n      \"ERC20Token: cannot transfer from 0x0 address\"\n    );\n    require(\n      to != address(0),\n      \"ERC20Token: cannot transfer to 0x0 address\"\n    );\n\n    balances[from] = balances[from].sub(value);\n    balances[to] = balances[to].add(value);\n\n    emit Transfer(from, to, value);\n  }\n\n  function _approve(\n    address owner,\n    address spender,\n    uint256 value\n  )\n    virtual\n    internal\n  {\n    require(\n      owner != address(0),\n      \"ERC20Token: cannot approve from 0x0 address\"\n    );\n    require(\n      spender != address(0),\n      \"ERC20Token: cannot approve to 0x0 address\"\n    );\n\n    allowances[owner][spender] = value;\n\n    emit Approval(owner, spender, value);\n  }\n\n  function _mint(\n    address owner,\n    uint256 value\n  )\n    virtual\n    internal\n  {\n    require(\n      owner != address(0),\n      \"ERC20Token: cannot mint to 0x0 address\"\n    );\n    require(\n      value > 0,\n      \"ERC20Token: cannot mint 0 value\"\n    );\n\n    balances[owner] = balances[owner].add(value);\n    totalSupply = totalSupply.add(value);\n\n    emit Transfer(address(0), owner, value);\n  }\n\n  function _burn(\n    address owner,\n    uint256 value\n  )\n    virtual\n    internal\n  {\n    require(\n      owner != address(0),\n      \"ERC20Token: cannot burn from 0x0 address\"\n    );\n\n    balances[owner] = balances[owner].sub(\n      value,\n      \"ERC20Token: burn value exceeds balance\"\n    );\n\n    totalSupply = totalSupply.sub(value);\n\n    emit Transfer(owner, address(0), value);\n  }\n\n  // internal functions (views)\n\n  function _getSender()\n    virtual\n    internal\n    view\n    returns (address)\n  {\n    return msg.sender;\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/external/ExternalAccountRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/BlockLib.sol\";\n\n\n/**\n * @title External account registry\n *\n * @notice Global registry for keys and external (outside of the platform) contract based wallets\n *\n * @dev An account can call the registry to add (`addAccountOwner`) or remove (`removeAccountOwner`) its own owners.\n * When the owner has been added, information about that fact will live in the registry forever.\n * Removing an owner only affects the future blocks (until the owner is re-added).\n *\n * Given the fact, there is no way to sign the data using a contract based wallet,\n * we created a registry to store signed by the key wallet proofs.\n * ERC-1271 allows removing a signer after the signature was created. Thus store the signature for the later use\n * doesn't guarantee the signer is still has access to that smart account.\n * Because of that, the ERC1271's `isValidSignature()` cannot be used in e.g. `PaymentRegistry`.*\n *\n * An account can call the registry to add (`addAccountProof`) or remove (`removeAccountProof`) proof hash.\n * When the proof has been added, information about that fact will live in the registry forever.\n * Removing a proof only affects the future blocks (until the proof is re-added).\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract ExternalAccountRegistry {\n  using BlockLib for BlockLib.BlockRelated;\n\n  struct Account {\n    mapping(address => BlockLib.BlockRelated) owners;\n    mapping(bytes32 => BlockLib.BlockRelated) proofs;\n  }\n\n  mapping(address => Account) private accounts;\n\n  // events\n\n  /**\n   * @dev Emitted when the new owner is added\n   * @param account account address\n   * @param owner owner address\n   */\n  event AccountOwnerAdded(\n    address account,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when the existing owner is removed\n   * @param account account address\n   * @param owner owner address\n   */\n  event AccountOwnerRemoved(\n    address account,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when the new proof is added\n   * @param account account address\n   * @param hash proof hash\n   */\n  event AccountProofAdded(\n    address account,\n    bytes32 hash\n  );\n\n  /**\n   * @dev Emitted when the existing proof is removed\n   * @param account account address\n   * @param hash proof hash\n   */\n  event AccountProofRemoved(\n    address account,\n    bytes32 hash\n  );\n\n  // external functions\n\n  /**\n   * @notice Adds a new account owner\n   * @param owner owner address\n   */\n  function addAccountOwner(\n    address owner\n  )\n    external\n  {\n    require(\n      owner != address(0),\n      \"ExternalAccountRegistry: cannot add 0x0 owner\"\n    );\n\n    require(\n      !accounts[msg.sender].owners[owner].verifyAtCurrentBlock(),\n      \"ExternalAccountRegistry: owner already exists\"\n    );\n\n    accounts[msg.sender].owners[owner].added = true;\n    accounts[msg.sender].owners[owner].removedAtBlockNumber = 0;\n\n    emit AccountOwnerAdded(\n      msg.sender,\n      owner\n    );\n  }\n\n  /**\n   * @notice Removes existing account owner\n   * @param owner owner address\n   */\n  function removeAccountOwner(\n    address owner\n  )\n    external\n  {\n    require(\n      accounts[msg.sender].owners[owner].verifyAtCurrentBlock(),\n      \"ExternalAccountRegistry: owner doesn't exist\"\n    );\n\n    accounts[msg.sender].owners[owner].removedAtBlockNumber = block.number;\n\n    emit AccountOwnerRemoved(\n      msg.sender,\n      owner\n    );\n  }\n\n  /**\n   * @notice Adds a new account proof\n   * @param hash proof hash\n   */\n  function addAccountProof(\n    bytes32 hash\n  )\n    external\n  {\n    require(\n      !accounts[msg.sender].proofs[hash].verifyAtCurrentBlock(),\n      \"ExternalAccountRegistry: proof already exists\"\n    );\n\n    accounts[msg.sender].proofs[hash].added = true;\n    accounts[msg.sender].proofs[hash].removedAtBlockNumber = 0;\n\n    emit AccountProofAdded(\n      msg.sender,\n      hash\n    );\n  }\n\n  /**\n   * @notice Removes existing account proof\n   * @param hash proof hash\n   */\n  function removeAccountProof(\n    bytes32 hash\n  )\n    external\n  {\n    require(\n      accounts[msg.sender].proofs[hash].verifyAtCurrentBlock(),\n      \"ExternalAccountRegistry: proof doesn't exist\"\n    );\n\n    accounts[msg.sender].proofs[hash].removedAtBlockNumber = block.number;\n\n    emit AccountProofRemoved(\n      msg.sender,\n      hash\n    );\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Verifies the owner of the account at current block\n   * @param account account address\n   * @param owner owner address\n   * @return true on correct account owner\n   */\n  function verifyAccountOwner(\n    address account,\n    address owner\n  )\n    external\n    view\n    returns (bool)\n  {\n    return accounts[account].owners[owner].verifyAtCurrentBlock();\n  }\n\n  /**\n   * @notice Verifies the owner of the account at specific block\n   * @param account account address\n   * @param owner owner address\n   * @param blockNumber block number to verify\n   * @return true on correct account owner\n   */\n  function verifyAccountOwnerAtBlock(\n    address account,\n    address owner,\n    uint256 blockNumber\n  )\n    external\n    view\n    returns (bool)\n  {\n    return accounts[account].owners[owner].verifyAtBlock(blockNumber);\n  }\n\n  /**\n   * @notice Verifies the proof of the account at current block\n   * @param account account address\n   * @param hash proof hash\n   * @return true on correct account proof\n   */\n  function verifyAccountProof(\n    address account,\n    bytes32 hash\n  )\n    external\n    view\n    returns (bool)\n  {\n    return accounts[account].proofs[hash].verifyAtCurrentBlock();\n  }\n\n  /**\n   * @notice Verifies the proof of the account at specific block\n   * @param account account address\n   * @param hash proof hash\n   * @param blockNumber block number to verify\n   * @return true on correct account proof\n   */\n  function verifyAccountProofAtBlock(\n    address account,\n    bytes32 hash,\n    uint256 blockNumber\n  )\n    external\n    view\n    returns (bool)\n  {\n    return accounts[account].proofs[hash].verifyAtBlock(blockNumber);\n  }\n}\n"
    },
    "src/personal/PersonalAccountRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/access/Guarded.sol\";\nimport \"../common/account/AccountController.sol\";\nimport \"../common/account/AccountRegistry.sol\";\nimport \"../common/libs/BlockLib.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/libs/SignatureLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/token/ERC20Token.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\n\n\n/**\n * @title Personal account registry\n *\n * @notice A registry for personal (controlled by owners) accounts\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract PersonalAccountRegistry is Guarded, AccountController, AccountRegistry, Initializable, GatewayRecipient {\n  using BlockLib for BlockLib.BlockRelated;\n  using SafeMathLib for uint256;\n  using SignatureLib for bytes32;\n  using SignatureLib for bytes;\n\n  struct Account {\n    bool deployed;\n    bytes32 salt;\n    mapping(address => BlockLib.BlockRelated) owners;\n  }\n\n  mapping(address => Account) private accounts;\n\n  // events\n\n  /**\n   * @dev Emitted when the new owner is added\n   * @param account account address\n   * @param owner owner address\n   */\n  event AccountOwnerAdded(\n    address account,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when the existing owner is removed\n   * @param account account address\n   * @param owner owner address\n   */\n  event AccountOwnerRemoved(\n    address account,\n    address owner\n  );\n\n  /**\n   * @dev Emitted when the call is refunded\n   * @param account account address\n   * @param beneficiary beneficiary address\n   * @param token token address\n   * @param value value\n   */\n  event AccountCallRefunded(\n    address account,\n    address beneficiary,\n    address token,\n    uint256 value\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `PersonalAccountRegistry` contract\n   * @param guardians_ array of guardians addresses\n   * @param accountImplementation_ account implementation address\n   * @param gateway_ `Gateway` contract address\n   */\n  function initialize(\n    address[] calldata guardians_,\n    address accountImplementation_,\n    address gateway_\n  )\n    external\n    onlyInitializer\n  {\n    // Guarded\n    _initializeGuarded(guardians_);\n\n    // AccountController\n    _initializeAccountController(address(this), accountImplementation_);\n\n    // GatewayRecipient\n    _initializeGatewayRecipient(gateway_);\n  }\n\n  /**\n   * @notice Upgrades `PersonalAccountRegistry` contract\n   * @param accountImplementation_ account implementation address\n   */\n  function upgrade(\n    address accountImplementation_\n  )\n    external\n    onlyGuardian\n  {\n    _setAccountImplementation(accountImplementation_, true);\n  }\n\n  /**\n   * @notice Deploys account\n   * @param account account address\n   */\n  function deployAccount(\n    address account\n  )\n    external\n  {\n    _verifySender(account);\n    _deployAccount(account);\n  }\n\n  /**\n   * @notice Upgrades account\n   * @param account account address\n   */\n  function upgradeAccount(\n    address account\n  )\n    external\n  {\n    _verifySender(account);\n    _upgradeAccount(account, true);\n  }\n\n  /**\n   * @notice Adds a new account owner\n   * @param account account address\n   * @param owner owner address\n   */\n  function addAccountOwner(\n    address account,\n    address owner\n  )\n    external\n  {\n    _verifySender(account);\n\n    require(\n      owner != address(0),\n      \"PersonalAccountRegistry: cannot add 0x0 owner\"\n    );\n\n    require(\n      !accounts[account].owners[owner].verifyAtCurrentBlock(),\n      \"PersonalAccountRegistry: owner already exists\"\n    );\n\n    accounts[account].owners[owner].added = true;\n    accounts[account].owners[owner].removedAtBlockNumber = 0;\n\n    emit AccountOwnerAdded(\n      account,\n      owner\n    );\n  }\n\n  /**\n   * @notice Removes the existing account owner\n   * @param account account address\n   * @param owner owner address\n   */\n  function removeAccountOwner(\n    address account,\n    address owner\n  )\n    external\n  {\n    address sender = _verifySender(account);\n\n    require(\n      owner != sender,\n      \"PersonalAccountRegistry: cannot remove self\"\n    );\n\n    require(\n      accounts[account].owners[owner].verifyAtCurrentBlock(),\n      \"PersonalAccountRegistry: owner doesn't exist\"\n    );\n\n    accounts[account].owners[owner].removedAtBlockNumber = block.number;\n\n    emit AccountOwnerRemoved(\n      account,\n      owner\n    );\n  }\n\n  /**\n   * @notice Executes account transaction\n   * @dev Deploys an account if not deployed yet\n   * @param account account address\n   * @param to to address\n   * @param value value\n   * @param data data\n   */\n  function executeAccountTransaction(\n    address account,\n    address to,\n    uint256 value,\n    bytes calldata data\n  )\n    external\n  {\n    _verifySender(account);\n\n    _deployAccount(account);\n\n    _executeAccountTransaction(\n      account,\n      to,\n      value,\n      data,\n      true\n    );\n  }\n\n  /**\n   * @notice Refunds account call\n   * @dev Deploys an account if not deployed yet\n   * @param account account address\n   * @param token token address\n   * @param value value\n   */\n  function refundAccountCall(\n    address account,\n    address token,\n    uint256 value\n  )\n    external\n  {\n    _verifySender(account);\n\n    _deployAccount(account);\n\n    /* solhint-disable avoid-tx-origin */\n\n    if (token == address(0)) {\n      _executeAccountTransaction(\n        account,\n        tx.origin,\n        value,\n        new bytes(0),\n        false\n      );\n    } else {\n      bytes memory response = _executeAccountTransaction(\n        account,\n        token,\n        0,\n        abi.encodeWithSelector(\n          ERC20Token(token).transfer.selector,\n          tx.origin,\n          value\n        ),\n        false\n      );\n\n      if (response.length > 0) {\n        require(\n          abi.decode(response, (bool)),\n          \"PersonalAccountRegistry: ERC20Token transfer reverted\"\n        );\n      }\n    }\n\n    emit AccountCallRefunded(\n      account,\n      tx.origin,\n      token,\n      value\n    );\n\n    /* solhint-enable avoid-tx-origin */\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Computes account address\n   * @param saltOwner salt owner address\n   * @return account address\n   */\n  function computeAccountAddress(\n    address saltOwner\n  )\n    external\n    view\n    returns (address)\n  {\n    return _computeAccountAddress(saltOwner);\n  }\n\n  /**\n   * @notice Checks if account is deployed\n   * @param account account address\n   * @return true when account is deployed\n   */\n  function isAccountDeployed(\n    address account\n  )\n    external\n    view\n    returns (bool)\n  {\n    return accounts[account].deployed;\n  }\n\n  /**\n   * @notice Verifies the owner of the account at the current block\n   * @param account account address\n   * @param owner owner address\n   * @return true on correct account owner\n   */\n  function verifyAccountOwner(\n    address account,\n    address owner\n  )\n    external\n    view\n    returns (bool)\n  {\n    return _verifyAccountOwner(account, owner);\n  }\n\n  /**\n   * @notice Verifies the owner of the account at a specific block\n   * @param account account address\n   * @param owner owner address\n   * @param blockNumber block number to verify\n   * @return true on correct account owner\n   */\n  function verifyAccountOwnerAtBlock(\n    address account,\n    address owner,\n    uint256 blockNumber\n  )\n    external\n    view\n    returns (bool)\n  {\n    bool result = false;\n\n    if (_verifyAccountOwner(account, owner)) {\n      result = true;\n    } else {\n      result = accounts[account].owners[owner].verifyAtBlock(blockNumber);\n    }\n\n    return result;\n  }\n\n  /**\n   * @notice Verifies account signature\n   * @param account account address\n   * @param messageHash message hash\n   * @param signature signature\n   * @return magic hash if valid\n   */\n  function isValidAccountSignature(\n    address account,\n    bytes32 messageHash,\n    bytes calldata signature\n  )\n    override\n    external\n    view\n    returns (bool)\n  {\n    return _verifyAccountOwner(\n      account,\n      messageHash.recoverAddress(signature)\n    );\n  }\n\n  /**\n   * @notice Verifies account signature\n   * @param account account address\n   * @param message message\n   * @param signature signature\n   * @return magic hash if valid\n   */\n  function isValidAccountSignature(\n    address account,\n    bytes calldata message,\n    bytes calldata signature\n  )\n    override\n    external\n    view\n    returns (bool)\n  {\n    return _verifyAccountOwner(\n      account,\n      message.toEthereumSignedMessageHash().recoverAddress(signature)\n    );\n  }\n\n  // private functions\n\n  function _verifySender(\n    address account\n  )\n    private\n    returns (address)\n  {\n    address sender = _getContextSender();\n\n    if (accounts[account].owners[sender].added) {\n      require(\n        accounts[account].owners[sender].removedAtBlockNumber == 0,\n        \"PersonalAccountRegistry: sender is not the account owner\"\n      );\n    } else {\n      require(\n        accounts[account].salt == 0,\n        \"PersonalAccountRegistry: sender is not the account owner\"\n      );\n\n      bytes32 salt = keccak256(\n        abi.encodePacked(sender)\n      );\n\n      require(\n        account == _computeAccountAddress(salt),\n        \"PersonalAccountRegistry: sender is not the account owner\"\n      );\n\n      accounts[account].salt = salt;\n      accounts[account].owners[sender].added = true;\n\n      emit AccountOwnerAdded(\n        account,\n        sender\n      );\n    }\n\n    return sender;\n  }\n\n  function _deployAccount(\n    address account\n  )\n    internal\n  {\n    if (!accounts[account].deployed) {\n      _deployAccount(\n        accounts[account].salt,\n        true\n      );\n\n      accounts[account].deployed = true;\n    }\n  }\n\n  // private functions (views)\n\n  function _computeAccountAddress(\n    address saltOwner\n  )\n    private\n    view\n    returns (address)\n  {\n    bytes32 salt = keccak256(\n      abi.encodePacked(saltOwner)\n    );\n\n    return _computeAccountAddress(salt);\n  }\n\n  function _verifyAccountOwner(\n    address account,\n    address owner\n  )\n    private\n    view\n    returns (bool)\n  {\n    bool result;\n\n    if (accounts[account].owners[owner].added) {\n      result = accounts[account].owners[owner].removedAtBlockNumber == 0;\n    } else if (accounts[account].salt == 0) {\n      result = account == _computeAccountAddress(owner);\n    }\n\n    return result;\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/common/libs/BlockLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Block library\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\nlibrary BlockLib {\n  struct BlockRelated {\n    bool added;\n    uint256 removedAtBlockNumber;\n  }\n\n  /**\n   * @notice Verifies self struct at current block\n   * @param self self struct\n   * @return true on correct self struct\n   */\n  function verifyAtCurrentBlock(\n    BlockRelated memory self\n  )\n    internal\n    view\n    returns (bool)\n  {\n    return verifyAtBlock(self, block.number);\n  }\n\n  /**\n   * @notice Verifies self struct at any block\n   * @param self self struct\n   * @return true on correct self struct\n   */\n  function verifyAtAnyBlock(\n    BlockRelated memory self\n  )\n    internal\n    pure\n    returns (bool)\n  {\n    return verifyAtBlock(self, 0);\n  }\n\n  /**\n   * @notice Verifies self struct at specific block\n   * @param self self struct\n   * @param blockNumber block number to verify\n   * @return true on correct self struct\n   */\n  function verifyAtBlock(\n    BlockRelated memory self,\n    uint256 blockNumber\n  )\n    internal\n    pure\n    returns (bool)\n  {\n    bool result = false;\n\n    if (self.added) {\n      if (self.removedAtBlockNumber == 0) {\n        result = true;\n      } else if (blockNumber == 0) {\n        result = true;\n      } else {\n        result = self.removedAtBlockNumber > blockNumber;\n      }\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/common/account/AccountController.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./Account.sol\";\n\n\n/**\n * @title Account controller\n *\n * @dev Contract module which provides Account deployment mechanism\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract AccountController {\n  address public accountRegistry;\n  address public accountImplementation;\n\n  // events\n\n  /**\n   * @dev Emitted when the account registry is updated\n   * @param accountRegistry account registry address\n   */\n  event AccountRegistryUpdated(\n    address accountRegistry\n  );\n\n  /**\n   * @dev Emitted when the account implementation is updated\n   * @param accountImplementation account implementation address\n   */\n  event AccountImplementationUpdated(\n    address accountImplementation\n  );\n\n  /**\n   * @dev Emitted when the account is deployed\n   * @param account account address\n   * @param accountImplementation account implementation address\n   */\n  event AccountDeployed(\n    address account,\n    address accountImplementation\n  );\n\n  /**\n   * @dev Emitted when the account is upgraded\n   * @param account account address\n   * @param accountImplementation account implementation address\n   */\n  event AccountUpgraded(\n    address account,\n    address accountImplementation\n  );\n\n  /**\n   * @dev Emitted when the transaction is executed\n   * @param account account address\n   * @param to to address\n   * @param value value\n   * @param data data\n   * @param response response\n   */\n  event AccountTransactionExecuted(\n    address account,\n    address to,\n    uint256 value,\n    bytes data,\n    bytes response\n  );\n\n  /**\n   * @dev Internal constructor\n   */\n  constructor() internal {}\n\n  // internal functions\n\n  /**\n   * @notice Initializes `AccountController` contract\n   * @param accountRegistry_ account registry address\n   * @param accountImplementation_ account implementation address\n   */\n  function _initializeAccountController(\n    address accountRegistry_,\n    address accountImplementation_\n  )\n    internal\n  {\n    _setAccountRegistry(accountRegistry_, false);\n    _setAccountImplementation(accountImplementation_, false);\n  }\n\n  /**\n   * @notice Sets account registry\n   * @param accountRegistry_ account registry address\n   * @param emitEvent it will emit event when flag is set to true\n   */\n  function _setAccountRegistry(\n    address accountRegistry_,\n    bool emitEvent\n  )\n    internal\n  {\n    require(\n      accountRegistry_ != address(0),\n      \"AccountController: cannot set account registry to 0x0\"\n    );\n\n    accountRegistry = accountRegistry_;\n\n    if (emitEvent) {\n      emit AccountRegistryUpdated(accountRegistry);\n    }\n  }\n\n  /**\n   * @notice Sets account implementation\n   * @param accountImplementation_ account implementation address\n   * @param emitEvent it will emit event when flag is set to true\n   */\n  function _setAccountImplementation(\n    address accountImplementation_,\n    bool emitEvent\n  )\n    internal\n  {\n    require(\n      accountImplementation_ != address(0),\n      \"AccountController: cannot set account Implementation to 0x0\"\n    );\n\n    accountImplementation = accountImplementation_;\n\n    if (emitEvent) {\n      emit AccountImplementationUpdated(accountImplementation);\n    }\n  }\n\n  /**\n   * @notice Deploys account\n   * @param salt CREATE2 salt\n   * @param emitEvent it will emit event when flag is set to true\n   * @return account address\n   */\n  function _deployAccount(\n    bytes32 salt,\n    bool emitEvent\n  )\n    internal\n    returns (address)\n  {\n    address account = address(new Account{salt: salt}(\n      accountRegistry,\n      accountImplementation\n    ));\n\n    if (emitEvent) {\n      emit AccountDeployed(\n        account,\n        accountImplementation\n      );\n    }\n\n    return account;\n  }\n\n  /**\n   * @notice Upgrades account\n   * @param account account address\n   * @param emitEvent it will emit event when flag is set to true\n   */\n  function _upgradeAccount(\n    address account,\n    bool emitEvent\n  )\n    internal\n  {\n    require(\n      Account(payable(account)).implementation() != accountImplementation,\n      \"AccountController: account already upgraded\"\n    );\n\n    Account(payable(account)).setImplementation(accountImplementation);\n\n    if (emitEvent) {\n      emit AccountUpgraded(\n        account,\n        accountImplementation\n      );\n    }\n  }\n\n  /**\n   * @notice Executes transaction from the account\n   * @param account account address\n   * @param to to address\n   * @param value value\n   * @param data data\n   * @param emitEvent it will emit event when flag is set to true\n   * @return transaction result\n   */\n  function _executeAccountTransaction(\n    address account,\n    address to,\n    uint256 value,\n    bytes memory data,\n    bool emitEvent\n  )\n    internal\n    returns (bytes memory)\n  {\n    require(\n      to != address(0),\n      \"AccountController: cannot send to 0x0\"\n    );\n\n    require(\n      to != address(this),\n      \"AccountController: cannot send to controller\"\n    );\n\n    require(\n      to != account,\n      \"AccountController: cannot send to self\"\n    );\n\n    bytes memory response = Account(payable(account)).executeTransaction(\n      to,\n      value,\n      data\n    );\n\n    if (emitEvent) {\n      emit AccountTransactionExecuted(\n        account,\n        to,\n        value,\n        data,\n        response\n      );\n    }\n\n    return response;\n  }\n\n  // internal functions (views)\n\n  /**\n   * @notice Computes account CREATE2 address\n   * @param salt CREATE2 salt\n   * @return account address\n   */\n  function _computeAccountAddress(\n    bytes32 salt\n  )\n    internal\n    view\n    returns (address)\n  {\n    bytes memory creationCode = abi.encodePacked(\n      type(Account).creationCode,\n      bytes12(0),\n      accountRegistry,\n      bytes12(0),\n      accountImplementation\n    );\n\n    bytes32 data = keccak256(\n      abi.encodePacked(\n        bytes1(0xff),\n        address(this),\n        salt,\n        keccak256(creationCode)\n      )\n    );\n\n    return address(uint160(uint256(data)));\n  }\n}\n"
    },
    "src/common/account/AccountRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./Account.sol\";\n\n\n/**\n * @title Account registry\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\nabstract contract AccountRegistry {\n  /**\n   * @notice Verifies account signature\n   * @param account account address\n   * @param messageHash message hash\n   * @param signature signature\n   * @return true if valid\n   */\n  function isValidAccountSignature(\n    address account,\n    bytes32 messageHash,\n    bytes calldata signature\n  )\n    virtual\n    external\n    view\n    returns (bool);\n\n  /**\n   * @notice Verifies account signature\n   * @param account account address\n   * @param message message\n   * @param signature signature\n   * @return true if valid\n   */\n  function isValidAccountSignature(\n    address account,\n    bytes calldata message,\n    bytes calldata signature\n  )\n    virtual\n    external\n    view\n    returns (bool);\n}\n"
    },
    "src/common/account/Account.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../access/Controlled.sol\";\nimport \"./AccountBase.sol\";\n\n\n/**\n * @title Account\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Account is Controlled, AccountBase {\n  address public implementation;\n\n  /**\n   * @dev Public constructor\n   * @param registry_ account registry address\n   * @param implementation_ account implementation address\n   */\n  constructor(\n    address registry_,\n    address implementation_\n  )\n    public\n    Controlled()\n  {\n    registry = registry_;\n    implementation = implementation_;\n  }\n\n  // external functions\n\n  /**\n   * @notice Payable receive\n   */\n  receive()\n    external\n    payable\n  {\n    //\n  }\n\n  /**\n   * @notice Fallback\n   */\n  // solhint-disable-next-line payable-fallback\n  fallback()\n    external\n  {\n    if (msg.data.length != 0) {\n      address implementation_ = implementation;\n\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        let calldedatasize := calldatasize()\n\n        calldatacopy(0, 0, calldedatasize)\n\n        let result := delegatecall(gas(), implementation_, 0, calldedatasize, 0, 0)\n        let returneddatasize := returndatasize()\n\n        returndatacopy(0, 0, returneddatasize)\n\n        switch result\n        case 0 { revert(0, returneddatasize) }\n        default { return(0, returneddatasize) }\n      }\n    }\n  }\n\n  /**\n   * @notice Sets implementation\n   * @param implementation_ implementation address\n   */\n  function setImplementation(\n    address implementation_\n  )\n    external\n    onlyController\n  {\n    implementation = implementation_;\n  }\n\n  /**\n   * @notice Executes transaction\n   * @param to to address\n   * @param value value\n   * @param data data\n   * @return transaction result\n   */\n  function executeTransaction(\n    address to,\n    uint256 value,\n    bytes calldata data\n  )\n    external\n    onlyController\n    returns (bytes memory)\n  {\n    bytes memory result;\n    bool succeeded;\n\n    // solhint-disable-next-line avoid-call-value, avoid-low-level-calls\n    (succeeded, result) = payable(to).call{value: value}(data);\n\n    require(\n      succeeded,\n      \"Account: transaction reverted\"\n    );\n\n    return result;\n  }\n}\n"
    },
    "src/common/account/AccountBase.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Account base\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract AccountBase {\n  address public registry;\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/tokens/WrappedWeiToken.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/token/ERC20Token.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\n\n\n/**\n * @title Wrapped wei token\n *\n * @notice One to one wei consumable ERC20 token\n *\n * @dev After the transfer to consumer's account is done, the token will be automatically burned and withdrawn.\n *\n * Use `startConsuming` to become a consumer.\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract WrappedWeiToken is Initializable, ERC20Token, GatewayRecipient {\n  mapping(address => bool) private consumers;\n\n  // events\n\n  /**\n   * @dev Emitted when the new consumer is added\n   * @param consumer consumer address\n   */\n  event ConsumerAdded(\n    address consumer\n  );\n\n  /**\n   * @dev Emitted when the existing consumer is removed\n   * @param consumer consumer address\n   */\n  event ConsumerRemoved(\n    address consumer\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor()\n    public\n    Initializable()\n  {\n    name = \"Wrapped Wei\";\n    symbol = \"WWEI\";\n  }\n\n  /**\n   * @notice Receive fallback\n   */\n  receive()\n    external\n    payable\n  {\n    _mint(_getSender(), msg.value);\n  }\n\n  // external functions\n\n  /**\n   * @notice Initializes `WrappedWeiToken` contract\n   * @param consumers_ array of consumers addresses\n   * @param gateway_ `Gateway` contract address\n   */\n  function initialize(\n    address[] calldata consumers_,\n    address gateway_\n  )\n    external\n    onlyInitializer\n  {\n    if (consumers_.length != 0) {\n      uint consumersLen = consumers_.length;\n      for (uint i = 0; i < consumersLen; i++) {\n        _addConsumer(consumers_[i]);\n      }\n    }\n\n    _initializeGatewayRecipient(gateway_);\n  }\n\n  /**\n   * @notice Starts consuming\n   * @dev Add caller as a consumer\n   */\n  function startConsuming()\n    external\n  {\n    _addConsumer(_getSender());\n  }\n\n  /**\n   * @notice Stops consuming\n   * @dev Remove caller from consumers\n   */\n  function stopConsuming()\n    external\n  {\n    address consumer = _getSender();\n\n    require(\n      consumers[consumer],\n      \"WrappedWeiToken: consumer doesn't exist\"\n    );\n\n    consumers[consumer] = false;\n\n    emit ConsumerRemoved(consumer);\n  }\n\n  /**\n   * @notice Deposits `msg.value` to address\n   * @param to to address\n   */\n  function depositTo(\n    address to\n  )\n    external\n    payable\n  {\n    _mint(to, msg.value);\n  }\n\n  /**\n   * @notice Withdraws\n   * @param value value to withdraw\n   */\n  function withdraw(\n    uint256 value\n  )\n    external\n  {\n    _withdraw(_getSender(), _getSender(), value);\n  }\n\n  /**\n   * @notice Withdraws to address\n   * @param to to address\n   * @param value value to withdraw\n   */\n  function withdrawTo(\n    address to,\n    uint256 value\n  )\n    external\n  {\n    _withdraw(_getSender(), to, value);\n  }\n\n  /**\n   * @notice Withdraws all\n   */\n  function withdrawAll()\n    external\n  {\n    address sender = _getSender();\n\n    _withdraw(sender, sender, balances[sender]);\n  }\n\n  /**\n   * @notice Withdraws all to address\n   * @param to to address\n   */\n  function withdrawAllTo(\n    address to\n  )\n    external\n  {\n    address sender = _getSender();\n\n    _withdraw(sender, to, balances[sender]);\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Checks if consumer exists\n   * @param consumer consumer address\n   * @return true if consumer exists\n   */\n  function isConsumer(\n    address consumer\n  )\n    external\n    view\n    returns (bool)\n  {\n    return consumers[consumer];\n  }\n\n  // internal functions\n\n  function _transfer(\n    address from,\n    address to,\n    uint256 value\n  )\n    override\n    internal\n  {\n    if (consumers[to]) {\n      _withdraw(from, to, value);\n    } else {\n      super._transfer(from, to, value);\n    }\n  }\n\n  // internal functions (views)\n\n  function _getSender()\n    override\n    internal\n    view\n    returns (address)\n  {\n    return _getContextAccount();\n  }\n\n  // private functions\n\n  function _addConsumer(\n    address consumer\n  )\n    private\n  {\n    require(\n      !consumers[consumer],\n      \"WrappedWeiToken: consumer already exists\"\n    );\n\n    consumers[consumer] = true;\n\n    emit ConsumerAdded(consumer);\n  }\n\n  function _withdraw(\n    address from,\n    address to,\n    uint256 value\n  )\n    private\n  {\n    _burn(from, value);\n\n    require(\n      // solhint-disable-next-line check-send-result\n      payable(to).send(value),\n      \"WrappedWeiToken: transaction reverted\"\n    );\n  }\n}\n"
    },
    "src/utils/Utils.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/token/ERC20Token.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\n\n\n/**\n * @title Utils\n *\n * @author Jegor Sidorenko <jegor@pillarproject.io>\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Utils {\n  using SafeMathLib for uint256;\n\n  // external functions\n\n  /**\n   * @notice Checks the token balances of accounts for multiple tokens.\n   * @dev Pass 0x0 as a \"token\" address to get ETH balance.\n   *\n   * Possible error throws:\n   * - extremely large arrays for account and or tokens (gas cost too high)\n   *\n   * @param accounts array of accounts addresses\n   * @param tokens array of tokens addresses\n   * @return a one-dimensional that's user.length * tokens.length long. The\n   * array is ordered by all of the 0th accounts token balances, then the 1th\n   * user, and so on.\n   */\n  function getBalances(\n    address[] calldata accounts,\n    address[] calldata tokens\n  )\n    external\n    view\n    returns (uint[] memory)\n  {\n    uint[] memory result = new uint[](accounts.length.mul(tokens.length));\n\n    for (uint i = 0; i < accounts.length; i++) {\n      for (uint j = 0; j < tokens.length; j++) {\n        uint index = j.add(tokens.length.mul(i));\n\n        if (tokens[j] != address(0x0)) {\n          result[index] = _getBalance(accounts[i], tokens[j]);\n        } else {\n          result[index] = accounts[i].balance;\n        }\n      }\n    }\n\n    return result;\n  }\n\n  // private functions\n\n  function _getBalance(\n    address account,\n    address token\n  )\n    private\n    view\n    returns (uint256)\n  {\n    uint256 result = 0;\n    uint256 tokenCode;\n\n    /// @dev check if token is actually a contract\n    // solhint-disable-next-line no-inline-assembly\n    assembly { tokenCode := extcodesize(token) } // contract code size\n\n    if (tokenCode > 0) {\n      /// @dev is it a contract and does it implement balanceOf\n      // solhint-disable-next-line avoid-low-level-calls\n      (bool methodExists,) = token.staticcall(abi.encodeWithSelector(\n        ERC20Token(token).balanceOf.selector,\n        account\n      ));\n\n      if (methodExists) {\n        result = ERC20Token(token).balanceOf(account);\n      }\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/gateway/Gateway.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/libs/SignatureLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/typedData/TypedDataContainer.sol\";\nimport \"../external/ExternalAccountRegistry.sol\";\nimport \"../personal/PersonalAccountRegistry.sol\";\n\n\n/**\n * @title Gateway\n *\n * @notice GSN replacement\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Gateway is Initializable, TypedDataContainer {\n  using SafeMathLib for uint256;\n  using SignatureLib for bytes32;\n\n  struct DelegatedBatch {\n    address account;\n    uint256 nonce;\n    address[] to;\n    bytes[] data;\n  }\n\n  struct DelegatedBatchWithGasPrice {\n    address account;\n    uint256 nonce;\n    address[] to;\n    bytes[] data;\n    uint256 gasPrice;\n  }\n\n  bytes32 private constant DELEGATED_BATCH_TYPE_HASH = keccak256(\n    \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\n  );\n\n  bytes32 private constant DELEGATED_BATCH_TYPE_HASH_WITH_GAS_PRICE = keccak256(\n    \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\n  );\n\n  ExternalAccountRegistry public externalAccountRegistry;\n  PersonalAccountRegistry public personalAccountRegistry;\n\n  mapping(address => uint256) private accountNonce;\n\n  // events\n\n  /**\n   * @dev Emitted when the single batch is delegated\n   * @param sender sender address\n   * @param batch batch\n   * @param succeeded if succeeded\n   */\n  event BatchDelegated(\n    address sender,\n    bytes batch,\n    bool succeeded\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `Gateway` contract\n   * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\n   * @param personalAccountRegistry_ `PersonalAccountRegistry` contract 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    ExternalAccountRegistry externalAccountRegistry_,\n    PersonalAccountRegistry personalAccountRegistry_,\n    bytes32 typedDataDomainNameHash,\n    bytes32 typedDataDomainVersionHash,\n    bytes32 typedDataDomainSalt\n  )\n    external\n    onlyInitializer\n  {\n    externalAccountRegistry = externalAccountRegistry_;\n    personalAccountRegistry = personalAccountRegistry_;\n\n    // TypedDataContainer\n    _initializeTypedDataContainer(\n      typedDataDomainNameHash,\n      typedDataDomainVersionHash,\n      typedDataDomainSalt\n    );\n  }\n\n  // public functions\n\n  /**\n   * @notice Sends batch\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `msg.sender`\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatch(\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n  {\n    _sendBatch(\n      msg.sender,\n      msg.sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Sends batch from the account\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param account account address\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatchFromAccount(\n    address account,\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n  {\n    _sendBatch(\n      account,\n      msg.sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates batch from the account\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatch(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n  {\n    require(\n      nonce > accountNonce[account],\n      \"Gateway: nonce is lower than current account nonce\"\n    );\n\n    address sender = _hashPrimaryTypedData(\n      _hashTypedData(\n        account,\n        nonce,\n        to,\n        data\n      )\n    ).recoverAddress(senderSignature);\n\n    accountNonce[account] = nonce;\n\n    _sendBatch(\n      account,\n      sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates batch from the account (with gas price)\n   *\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatchWithGasPrice(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n  {\n    require(\n      nonce > accountNonce[account],\n      \"Gateway: nonce is lower than current account nonce\"\n    );\n\n    address sender = _hashPrimaryTypedData(\n      _hashTypedData(\n        account,\n        nonce,\n        to,\n        data,\n        tx.gasprice\n      )\n    ).recoverAddress(senderSignature);\n\n    accountNonce[account] = nonce;\n\n    _sendBatch(\n      account,\n      sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates multiple batches\n   * @dev It will revert when all batches fail\n   * @param batches array of batches\n   * @param revertOnFailure reverts on any error\n   */\n  function delegateBatches(\n    bytes[] memory batches,\n    bool revertOnFailure\n  )\n    public\n  {\n    require(\n      batches.length > 0,\n      \"Gateway: cannot delegate empty batches\"\n    );\n\n    bool anySucceeded;\n\n    for (uint256 i = 0; i < batches.length; i++) {\n      // solhint-disable-next-line avoid-low-level-calls\n      (bool succeeded,) = address(this).call(batches[i]);\n\n      if (revertOnFailure) {\n        require(\n          succeeded,\n          \"Gateway: batch reverted\"\n        );\n      } else if (succeeded && !anySucceeded) {\n        anySucceeded = true;\n      }\n\n      emit BatchDelegated(\n        msg.sender,\n        batches[i],\n        succeeded\n      );\n    }\n\n    if (!anySucceeded) {\n      revert(\"Gateway: all batches reverted\");\n    }\n  }\n\n  // public functions (views)\n\n  /**\n   * @notice Hashes `DelegatedBatch` typed data\n   * @param delegatedBatch struct\n   * @return hash\n   */\n  function hashDelegatedBatch(\n    DelegatedBatch memory delegatedBatch\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashPrimaryTypedData(\n      _hashTypedData(\n        delegatedBatch.account,\n        delegatedBatch.nonce,\n        delegatedBatch.to,\n        delegatedBatch.data\n      )\n    );\n  }\n\n  /**\n   * @notice Hashes `DelegatedBatchWithGasPrice` typed data\n   * @param delegatedBatch struct\n   * @return hash\n   */\n  function hashDelegatedBatchWithGasPrice(\n    DelegatedBatchWithGasPrice memory delegatedBatch\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashPrimaryTypedData(\n      _hashTypedData(\n        delegatedBatch.account,\n        delegatedBatch.nonce,\n        delegatedBatch.to,\n        delegatedBatch.data,\n        delegatedBatch.gasPrice\n      )\n    );\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Gets next account nonce\n   * @param account account address\n   * @return next nonce\n   */\n  function getAccountNextNonce(\n    address account\n  )\n    external\n    view\n    returns (uint256)\n  {\n    return accountNonce[account].add(1);\n  }\n\n  // private functions\n\n  function _sendBatch(\n    address account,\n    address sender,\n    address[] memory to,\n    bytes[] memory data\n  )\n    private\n  {\n    require(\n      account != address(0),\n      \"Gateway: cannot send from 0x0 account\"\n    );\n    require(\n      to.length > 0,\n      \"Gateway: cannot send empty batch\"\n    );\n    require(\n      data.length == to.length,\n      \"Gateway: invalid batch\"\n    );\n\n    if (account != sender) {\n      require(\n        personalAccountRegistry.verifyAccountOwner(account, sender) ||\n        externalAccountRegistry.verifyAccountOwner(account, sender),\n        \"Gateway: sender is not the account owner\"\n      );\n    }\n\n    bool succeeded;\n\n    for (uint256 i = 0; i < data.length; i++) {\n      require(\n        to[i] != address(0),\n        \"Gateway: cannot send to 0x0\"\n      );\n\n      // solhint-disable-next-line avoid-low-level-calls\n      (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\n\n      require(\n        succeeded,\n        \"Gateway: batch transaction reverted\"\n      );\n    }\n  }\n\n  // private functions (pure)\n\n  function _hashTypedData(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data\n  )\n    private\n    pure\n    returns (bytes32)\n  {\n    bytes32[] memory dataHashes = new bytes32[](data.length);\n\n    for (uint256 i = 0; i < data.length; i++) {\n      dataHashes[i] = keccak256(data[i]);\n    }\n\n    return keccak256(abi.encode(\n      DELEGATED_BATCH_TYPE_HASH,\n      account,\n      nonce,\n      keccak256(abi.encodePacked(to)),\n      keccak256(abi.encodePacked(dataHashes))\n    ));\n  }\n\n  function _hashTypedData(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    uint256 gasPrice\n  )\n    private\n    pure\n    returns (bytes32)\n  {\n    bytes32[] memory dataHashes = new bytes32[](data.length);\n\n    for (uint256 i = 0; i < data.length; i++) {\n      dataHashes[i] = keccak256(data[i]);\n    }\n\n    return keccak256(abi.encode(\n        DELEGATED_BATCH_TYPE_HASH_WITH_GAS_PRICE,\n        account,\n        nonce,\n        keccak256(abi.encodePacked(to)),\n        keccak256(abi.encodePacked(dataHashes)),\n        gasPrice\n      ));\n  }\n}\n"
    },
    "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 \"./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 {\n  struct Node {\n    address addr;\n    address owner;\n  }\n\n  struct SubNodeRegistration {\n    address account;\n    bytes32 node;\n    bytes32 label;\n  }\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 => Node) private nodes;\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      nodes[node].addr == address(0),\n      \"ENSController: node already exists\"\n    );\n\n    require(\n      nodes[node].owner == 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    nodes[node].owner = 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      nodes[node].addr == address(0),\n      \"ENSController: node already exists\"\n    );\n\n    require(\n      nodes[node].owner == 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    nodes[node].addr = 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      nodes[node].addr == address(this),\n      \"ENSController: node doesn't exist\"\n    );\n\n    require(\n      nodes[node].owner == owner,\n      \"ENSController: invalid node owner\"\n    );\n\n    registry.setOwner(node, owner);\n\n    delete nodes[node].addr;\n    delete nodes[node].owner;\n\n    emit NodeReleased(node, owner);\n  }\n\n  /**\n   * @notice Sets address\n   * @dev Used in address resolver\n   * @param node node name hash\n   * @param addr address\n   */\n  function setAddr(\n    bytes32 node,\n    address addr\n  )\n    external\n  {\n    require(\n      nodes[node].addr == _getContextAccount(),\n      \"ENSController: caller is not the node owner\"\n    );\n\n    nodes[node].addr = addr;\n\n    emit AddrChanged(node, addr);\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      nodes[node].addr == address(0),\n      \"ENSController: node already in sync\"\n    );\n\n    nodes[node].addr = account;\n\n    emit AddrChanged(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      nodes[node].addr == address(this),\n      \"ENSController: invalid node\"\n    );\n\n    require(\n      nodes[subNode].addr == address(0),\n      \"ENSController: label already taken\"\n    );\n\n    nodes[subNode].addr = account;\n\n    registry.setSubnodeOwner(node, label, address(this));\n    registry.setResolver(subNode, address(this));\n    registry.setOwner(subNode, account);\n\n    emit AddrChanged(subNode, account);\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Gets address\n   * @dev Used in address resolver\n   * @param node node name hash\n   * @return node address\n   */\n  function addr(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    return nodes[node].addr;\n  }\n  /**\n   * @notice Gets node\n   * @param node node name hash\n   */\n  function getNode(\n    bytes32 node\n  )\n    external\n    view\n    returns (address nodeAddr, address nodeOwner)\n  {\n    return (nodes[node].addr, nodes[node].owner);\n  }\n\n  // external functions (pure)\n\n  /**\n   * @notice Checks if contract supports interface\n   * @param interfaceID method signature\n   * @return true when contract supports interface\n   */\n  function supportsInterface(\n    bytes4 interfaceID\n  )\n    external\n    pure\n    returns (bool)\n  {\n    return (\n      /// @dev bytes4(keccak256('supportsInterface(bytes4)'));\n      interfaceID == 0x01ffc9a7 ||\n      /// @dev bytes4(keccak256('addr(bytes32)'));\n      interfaceID == 0x3b3b57de\n    );\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  // 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/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/v0.2.2/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\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  // modifiers\n\n  modifier onlyNodeOwner(\n    bytes32 node\n  ) {\n    require(\n      records[node].owner == msg.sender,\n      \"ENSRegistry: msg.sender is not the node owner\"\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 setOwner(\n    bytes32 node,\n    address owner\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    records[node].owner = owner;\n\n    emit Transfer(node, owner);\n  }\n\n  function setSubnodeOwner(\n    bytes32 node,\n    bytes32 label,\n    address owner\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    bytes32 subNode = keccak256(\n      abi.encodePacked(\n        node,\n        label\n      )\n    );\n\n    records[subNode].owner = owner;\n\n    emit NewOwner(node, label, owner);\n  }\n\n  function setResolver(\n    bytes32 node,\n    address resolver\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    records[node].resolver = resolver;\n\n    emit NewResolver(node, resolver);\n  }\n\n  function setTTL(\n    bytes32 node,\n    uint64 ttl\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    records[node].ttl = ttl;\n\n    emit NewTTL(node, ttl);\n  }\n\n  // external functions (views)\n\n  function owner(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    return records[node].owner;\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"
    },
    "src/common/access/mocks/GuardedMock.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../Guarded.sol\";\n\n\n/**\n * @title Guarded mock\n *\n * @dev Used in `Guarded` contract tests\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract GuardedMock is Guarded {\n  /**\n   * @dev Public constructor\n   * @param guardians_ array of guardians addresses\n   */\n  constructor(\n    address[] memory guardians_\n  )\n    public\n  {\n    _initializeGuarded(guardians_);\n  }\n}\n"
    },
    "src/common/account/mocks/AccountRegistryMock.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../../libs/SignatureLib.sol\";\nimport \"../AccountRegistry.sol\";\n\n\n/**\n * @title Account registry mock\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract AccountRegistryMock is AccountRegistry {\n  using SignatureLib for bytes32;\n  using SignatureLib for bytes;\n\n  mapping(address => mapping(address => bool)) private mockedAccountsOwners;\n\n  // external functions\n\n  function mockAccountOwners(\n    address account,\n    address[] memory owners\n  )\n    external\n  {\n    uint ownersLen = owners.length;\n    for (uint i = 0; i < ownersLen; i++) {\n      mockedAccountsOwners[account][owners[i]] = true;\n    }\n  }\n\n  // external functions (views)\n\n  function isValidAccountSignature(\n    address account,\n    bytes32 messageHash,\n    bytes calldata signature\n  )\n    override\n    external\n    view\n    returns (bool)\n  {\n    address recovered = messageHash.recoverAddress(signature);\n\n    return mockedAccountsOwners[account][recovered];\n  }\n\n  function isValidAccountSignature(\n    address account,\n    bytes calldata message,\n    bytes calldata signature\n  )\n    override\n    external\n    view\n    returns (bool)\n  {\n    address recovered = message.toEthereumSignedMessageHash().recoverAddress(signature);\n\n    return mockedAccountsOwners[account][recovered];\n  }\n}\n"
    },
    "src/common/account/mocks/AccountControllerMock.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../AccountController.sol\";\n\n\n/**\n * @title Account controller mock\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract AccountControllerMock is AccountController {\n  /**\n   * @dev Public constructor\n   * @param accountRegistry_ account registry address\n   * @param accountImplementation_ account implementation address\n   */\n  constructor(\n    address accountRegistry_,\n    address accountImplementation_\n  )\n    public\n    AccountController()\n  {\n    _initializeAccountController(accountRegistry_, accountImplementation_);\n  }\n\n  // external functions\n\n  /**\n   * @notice Sets account registry\n   * @param accountRegistry_ account registry address\n   */\n  function setAccountRegistry(\n    address accountRegistry_\n  )\n    external\n  {\n    _setAccountRegistry(accountRegistry_, true);\n  }\n\n  /**\n   * @notice Sets account implementation\n   * @param accountImplementation_ account implementation address\n   */\n  function setAccountImplementation(\n    address accountImplementation_\n  )\n    external\n  {\n    _setAccountImplementation(accountImplementation_, true);\n  }\n\n  /**\n   * @notice Deploys account\n   * @param salt CREATE2 salt\n   */\n  function deployAccount(\n    bytes32 salt\n  )\n    external\n  {\n    _deployAccount(salt, true);\n  }\n\n  /**\n   * @notice Upgrades account\n   * @param account account address\n   */\n  function upgradeAccount(\n    address account\n  )\n    external\n  {\n    _upgradeAccount(account, true);\n  }\n\n  /**\n   * @notice Executes transaction from the account\n   * @param account account address\n   * @param to to address\n   * @param value value\n   * @param data data\n   */\n  function executeAccountTransaction(\n    address account,\n    address to,\n    uint256 value,\n    bytes memory data\n  )\n    external\n  {\n    _executeAccountTransaction(account, to, value, data, true);\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Computes account CREATE2 address\n   * @param salt CREATE2 salt\n   * @return account address\n   */\n  function computeAccountAddress(\n    bytes32 salt\n  )\n    external\n    view\n    returns (address)\n  {\n    return _computeAccountAddress(salt);\n  }\n}\n"
    },
    "src/common/account/AccountImplementationV1.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../lifecycle/Initializable.sol\";\nimport \"./AccountBase.sol\";\nimport \"./AccountRegistry.sol\";\n\n\n/**\n * @title Account implementation (version 1)\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract AccountImplementationV1 is Initializable, AccountBase {\n  bytes32 constant private ERC777_TOKENS_RECIPIENT_INTERFACE_HASH = keccak256(abi.encodePacked(\"ERC777TokensRecipient\"));\n  bytes32 constant private ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC1820_ACCEPT_MAGIC\"));\n\n  bytes4 constant private ERC1271_VALID_MESSAGE_HASH_SIGNATURE = bytes4(keccak256(abi.encodePacked(\"isValidSignature(bytes32,bytes)\")));\n  bytes4 constant private ERC1271_VALID_MESSAGE_SIGNATURE = bytes4(keccak256(abi.encodePacked(\"isValidSignature(bytes,bytes)\")));\n  bytes4 constant private ERC1271_INVALID_SIGNATURE = 0xffffffff;\n\n  /**\n   * @dev Internal constructor\n   */\n  constructor() internal Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `AccountImplementation` contract\n   * @param registry_ registry address\n   */\n  function initialize(\n    address registry_\n  )\n    external\n    onlyInitializer\n  {\n    registry = registry_;\n  }\n\n  // external functions (views)\n\n  // ERC1820\n\n  function canImplementInterfaceForAddress(\n    bytes32 interfaceHash,\n    address addr\n  )\n    external\n    view\n    returns(bytes32)\n  {\n    bytes32 result;\n\n    if (interfaceHash == ERC777_TOKENS_RECIPIENT_INTERFACE_HASH && addr == address(this)) {\n      result =  ERC1820_ACCEPT_MAGIC;\n    }\n\n    return result;\n  }\n\n  // ERC1271\n\n  function isValidSignature(\n    bytes32 messageHash,\n    bytes calldata signature\n  )\n    external\n    view\n    returns (bytes4)\n  {\n    return AccountRegistry(registry).isValidAccountSignature(address(this), messageHash, signature)\n      ? ERC1271_VALID_MESSAGE_HASH_SIGNATURE\n      : ERC1271_INVALID_SIGNATURE;\n  }\n\n  function isValidSignature(\n    bytes calldata message,\n    bytes calldata signature\n  )\n    external\n    view\n    returns (bytes4)\n  {\n    return AccountRegistry(registry).isValidAccountSignature(address(this), message, signature)\n      ? ERC1271_VALID_MESSAGE_SIGNATURE\n      : ERC1271_INVALID_SIGNATURE;\n  }\n\n  // external functions (pure)\n\n  // ERC721\n\n  function onERC721Received(\n    address,\n    address,\n    uint256,\n    bytes calldata\n  )\n    external\n    pure\n    returns (bytes4)\n  {\n    return this.onERC721Received.selector;\n  }\n\n  // ERC1155\n\n  function onERC1155Received(\n    address,\n    address,\n    uint256,\n    uint256,\n    bytes calldata\n  )\n    external\n    pure\n    returns (bytes4)\n  {\n    return this.onERC1155Received.selector;\n  }\n\n  // ERC777\n\n  function tokensReceived(\n    address,\n    address,\n    address,\n    uint256,\n    bytes calldata,\n    bytes calldata\n  )\n    external\n    pure\n  {}\n}\n"
    },
    "src/personal/PersonalAccountImplementationV1.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/account/AccountImplementationV1.sol\";\n\n\n/**\n * @title Personal account implementation (version 1)\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract PersonalAccountImplementationV1 is AccountImplementationV1 {\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public AccountImplementationV1() {}\n}\n"
    },
    "src/common/account/mocks/AccountImplementationV1Mock.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../AccountImplementationV1.sol\";\n\n\n/**\n * @title Account implementation mock (version 1)\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract AccountImplementationV1Mock is AccountImplementationV1 {\n  /**\n   * @dev Public constructor\n   * @param registry_ account registry address\n   */\n  constructor(\n    address registry_\n  )\n    public\n    AccountImplementationV1()\n  {\n    registry = registry_;\n  }\n}\n"
    },
    "src/gateway/mocks/GatewayRecipientMock.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../GatewayRecipient.sol\";\n\n\n/**\n * @title Gateway recipient mock\n *\n * @dev Used in `GatewayRecipient` contract tests\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract GatewayRecipientMock is GatewayRecipient {\n  // events\n\n  event Context(\n    address account,\n    address sender,\n    bytes data\n  );\n\n  /**\n   * @dev Public constructor\n   * @param gateway_ `Gateway` contract address\n   */\n  constructor(\n    address gateway_\n  )\n    public\n  {\n    _initializeGatewayRecipient(gateway_);\n  }\n\n  function emitContext()\n    external\n  {\n    emit Context(\n      _getContextAccount(),\n      _getContextSender(),\n      _getContextData()\n    );\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"
        ]
      }
    }
  }
}