{
  "language": "Solidity",
  "sources": {
    "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/ECDSALib.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/signature/SignatureValidator.sol\";\nimport \"../common/token/ERC20Token.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, SignatureValidator, GatewayRecipient {\n  using ECDSALib for bytes32;\n  using SafeMathLib for uint256;\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\n  bytes32 private constant HASH_PREFIX_DEPOSIT_WITHDRAWAL = keccak256(\n    \"DepositWithdrawal(address owner,address token,uint256 amount)\"\n  );\n  bytes32 private constant HASH_PREFIX_PAYMENT_CHANNEL_COMMIT = 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 Initializable() SignatureValidator() {}\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   */\n  function initialize(\n    ExternalAccountRegistry externalAccountRegistry_,\n    PersonalAccountRegistry personalAccountRegistry_,\n    uint256 depositExitLockPeriod_,\n    address[] calldata guardians_,\n    address gateway_\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\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 = _hashDepositWithdrawal(\n      owner,\n      token,\n      amount\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` message payload\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 _hashDepositWithdrawal(\n      depositWithdrawal.owner,\n      depositWithdrawal.token,\n      depositWithdrawal.amount\n    );\n  }\n\n  /**\n   * @notice Hashes `PaymentChannelCommit` message payload\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 _hashPaymentChannelCommit(\n      paymentChannelCommit.sender,\n      paymentChannelCommit.recipient,\n      paymentChannelCommit.token,\n      paymentChannelCommit.uid,\n      paymentChannelCommit.blockNumber,\n      paymentChannelCommit.amount\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 = _hashPaymentChannelCommit(\n      sender,\n      recipient,\n      token,\n      uid,\n      blockNumber,\n      amount\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  function _hashDepositWithdrawal(\n    address owner,\n    address token,\n    uint256 amount\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_DEPOSIT_WITHDRAWAL, abi.encodePacked(\n      owner,\n      token,\n      amount\n    ));\n  }\n\n  function _hashPaymentChannelCommit(\n    address sender,\n    address recipient,\n    address token,\n    bytes32 uid,\n    uint256 blockNumber,\n    uint256 amount\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_PAYMENT_CHANNEL_COMMIT, abi.encodePacked(\n      sender,\n      recipient,\n      token,\n      uid,\n      blockNumber,\n      amount\n    ));\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"
    },
    "src/common/access/Guarded.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/ECDSALib.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 ECDSALib 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/ECDSALib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ECDSA library\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/cryptography/ECDSA.sol#L26\n */\nlibrary ECDSALib {\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    bytes32 messageHash\n  )\n    internal\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encodePacked(\n      \"\\x19Ethereum Signed Message:\\n32\",\n      messageHash\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/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/signature/SignatureValidator.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/ECDSALib.sol\";\n\n/**\n * @title Signature validator\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract SignatureValidator {\n  using ECDSALib for bytes32;\n\n  uint256 public chainId;\n\n  /**\n   * @dev internal constructor\n   */\n  constructor() internal {\n    uint256 chainId_;\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      chainId_ := chainid()\n    }\n\n    chainId = chainId_;\n  }\n\n  // internal functions\n\n  function _hashMessagePayload(\n    bytes32 messagePrefix,\n    bytes memory messagePayload\n  )\n    internal\n    view\n    returns (bytes32)\n  {\n    return keccak256(abi.encodePacked(\n      chainId,\n      address(this),\n      messagePrefix,\n      messagePayload\n    )).toEthereumSignedMessageHash();\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/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/ECDSALib.sol\";\nimport \"../common/libs/ECDSAExtendedLib.sol\";\nimport \"../common/libs/SafeMathLib.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 ECDSALib for bytes32;\n  using ECDSAExtendedLib 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/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/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/libs/ECDSAExtendedLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./StringsLib.sol\";\n\n\n/**\n * @title ECDSA extended library\n */\nlibrary ECDSAExtendedLib {\n  using StringsLib for uint;\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      message.length.toString(),\n      abi.encodePacked(message)\n    ));\n  }\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/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/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/StringsLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Strings library\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/utils/Strings.sol#L12\n */\nlibrary StringsLib {\n  function toString(\n    uint256 value\n  )\n    internal\n    pure\n    returns (string memory)\n  {\n    if (value == 0) {\n      return \"0\";\n    }\n\n    uint256 temp = value;\n    uint256 digits;\n\n    while (temp != 0) {\n      digits++;\n      temp /= 10;\n    }\n\n    bytes memory buffer = new bytes(digits);\n    uint256 index = digits - 1;\n    temp = value;\n\n    while (temp != 0) {\n      buffer[index--] = byte(uint8(48 + temp % 10));\n      temp /= 10;\n    }\n\n    return string(buffer);\n  }\n}\n"
    },
    "src/common/libs/BytesLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Bytes library\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\nlibrary BytesLib {\n  /**\n   * @notice Converts bytes to address\n   * @param data data\n   * @return address\n   */\n  function toAddress(\n    bytes memory data\n  )\n    internal\n    pure\n    returns (address)\n  {\n    address result;\n\n    require(\n      data.length == 20,\n      \"BytesLib: invalid data length\"\n    );\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      result := div(mload(add(data, 0x20)), 0x1000000000000000000000000)\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/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/gateway/GatewayV2.sol": {
      "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.12;\r\npragma experimental ABIEncoderV2;\r\n\r\nimport \"../common/access/Guarded.sol\";\r\nimport \"../common/libs/ECDSALib.sol\";\r\nimport \"../common/libs/SafeMathLib.sol\";\r\nimport \"../common/lifecycle/Initializable.sol\";\r\nimport \"../common/signature/SignatureValidator.sol\";\r\nimport \"../external/ExternalAccountRegistry.sol\";\r\nimport \"../personal/PersonalAccountRegistry.sol\";\r\n\r\n/**\r\n * @title Gateway V2 with guarded batching functions\r\n *\r\n * @notice GSN replacement\r\n *\r\n * @author Utkir Sobirov <sobirovutkir@gmail.io>\r\n */\r\ncontract GatewayV2 is Initializable, SignatureValidator, Guarded {\r\n  using ECDSALib for bytes32;\r\n  using SafeMathLib for uint256;\r\n\r\n  struct DelegatedBatch {\r\n    address account;\r\n    uint256 nonce;\r\n    address[] to;\r\n    bytes[] data;\r\n  }\r\n\r\n  struct DelegatedBatchWithGasPrice {\r\n    address account;\r\n    uint256 nonce;\r\n    address[] to;\r\n    bytes[] data;\r\n    uint256 gasPrice;\r\n  }\r\n\r\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH = keccak256(\r\n    \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\r\n  );\r\n\r\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE = keccak256(\r\n    \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\r\n  );\r\n\r\n  ExternalAccountRegistry public externalAccountRegistry;\r\n  PersonalAccountRegistry public personalAccountRegistry;\r\n\r\n  mapping(address => uint256) private accountNonce;\r\n\r\n  // events\r\n\r\n  /**\r\n   * @dev Emitted when the single batch is delegated\r\n   * @param sender sender address\r\n   * @param batch batch\r\n   * @param succeeded if succeeded\r\n   */\r\n  event BatchDelegated(\r\n    address sender,\r\n    bytes batch,\r\n    bool succeeded\r\n  );\r\n\r\n  /**\r\n   * @dev Public constructor\r\n   */\r\n  constructor() public Initializable() SignatureValidator() {}\r\n\r\n  // external functions\r\n\r\n  /**\r\n   * @notice Initializes `Gateway` contract\r\n   * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\r\n   * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\r\n   */\r\n  function initialize(\r\n    ExternalAccountRegistry externalAccountRegistry_,\r\n    PersonalAccountRegistry personalAccountRegistry_\r\n  )\r\n    external\r\n    onlyInitializer\r\n  {\r\n    externalAccountRegistry = externalAccountRegistry_;\r\n    personalAccountRegistry = personalAccountRegistry_;\r\n\r\n    address[] memory guardians;\r\n    _initializeGuarded(guardians); // adds tx.origin to guardians list\r\n  }\r\n\r\n  // public functions\r\n\r\n  /**\r\n   * @notice Sends batch\r\n   * @dev `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `msg.sender`\r\n   * `_getContextSender` will return `msg.sender`\r\n   *\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   */\r\n  function sendBatch(\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    public\r\n  {\r\n    _sendBatch(\r\n      msg.sender,\r\n      msg.sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Sends guarded batch\r\n   * @dev `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `msg.sender`\r\n   * `_getContextSender` will return `msg.sender`\r\n   *\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   */\r\n  function sendBatchGuarded(\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    public\r\n    onlyGuardian\r\n  {\r\n    sendBatch(to, data);\r\n  }\r\n\r\n  /**\r\n   * @notice Sends batch from the account\r\n   * @dev `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return `msg.sender`\r\n   *\r\n   * @param account account address\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   */\r\n  function sendBatchFromAccount(\r\n    address account,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    public\r\n  {\r\n    _sendBatch(\r\n      account,\r\n      msg.sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Sends guarded batch from the account\r\n   * @dev `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return `msg.sender`\r\n   *\r\n   * @param account account address\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   */\r\n  function sendBatchFromAccountGuarded(\r\n    address account,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    public\r\n    onlyGuardian\r\n  {\r\n    sendBatchFromAccount(account, to, data);\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates batch from the account\r\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\r\n   *\r\n   * `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return recovered address from `senderSignature` arg\r\n   *\r\n   * @param account account address\r\n   * @param nonce next account nonce\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   * @param senderSignature sender signature\r\n   */\r\n  function delegateBatch(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    bytes memory senderSignature\r\n  )\r\n    public\r\n  {\r\n    require(\r\n      nonce > accountNonce[account],\r\n      \"Gateway: nonce is lower than current account nonce\"\r\n    );\r\n\r\n    address sender = _hashDelegatedBatch(\r\n      account,\r\n      nonce,\r\n      to,\r\n      data\r\n    ).recoverAddress(senderSignature);\r\n\r\n    accountNonce[account] = nonce;\r\n\r\n    _sendBatch(\r\n      account,\r\n      sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates guarded batch from the account\r\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\r\n   *\r\n   * `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return recovered address from `senderSignature` arg\r\n   *\r\n   * @param account account address\r\n   * @param nonce next account nonce\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   * @param senderSignature sender signature\r\n   */\r\n  function delegateBatchGuarded(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    bytes memory senderSignature\r\n  )\r\n    public\r\n    onlyGuardian\r\n  {\r\n    delegateBatch(account, nonce, to, data, senderSignature);\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates batch from the account (with gas price)\r\n   *\r\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\r\n   *\r\n   * `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return recovered address from `senderSignature` arg\r\n   *\r\n   * @param account account address\r\n   * @param nonce next account nonce\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   * @param senderSignature sender signature\r\n   */\r\n  function delegateBatchWithGasPrice(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    bytes memory senderSignature\r\n  )\r\n    public\r\n  {\r\n    require(\r\n      nonce > accountNonce[account],\r\n      \"Gateway: nonce is lower than current account nonce\"\r\n    );\r\n\r\n    address sender = _hashDelegatedBatchWithGasPrice(\r\n      account,\r\n      nonce,\r\n      to,\r\n      data,\r\n      tx.gasprice\r\n    ).recoverAddress(senderSignature);\r\n\r\n    accountNonce[account] = nonce;\r\n\r\n    _sendBatch(\r\n      account,\r\n      sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates guarded batch from the account (with gas price)\r\n   *\r\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\r\n   *\r\n   * `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return recovered address from `senderSignature` arg\r\n   *\r\n   * @param account account address\r\n   * @param nonce next account nonce\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   * @param senderSignature sender signature\r\n   */\r\n  function delegateBatchWithGasPriceGuarded(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    bytes memory senderSignature\r\n  )\r\n    public\r\n    onlyGuardian\r\n  {\r\n    delegateBatchWithGasPrice(account, nonce, to, data, senderSignature);\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates multiple batches\r\n   * @dev It will revert when all batches fail\r\n   * @param batches array of batches\r\n   * @param revertOnFailure reverts on any error\r\n   */\r\n  function delegateBatches(\r\n    bytes[] memory batches,\r\n    bool revertOnFailure\r\n  )\r\n    public\r\n  {\r\n    require(\r\n      batches.length > 0,\r\n      \"Gateway: cannot delegate empty batches\"\r\n    );\r\n\r\n    bool anySucceeded;\r\n\r\n    for (uint256 i = 0; i < batches.length; i++) {\r\n      // solhint-disable-next-line avoid-low-level-calls\r\n      (bool succeeded,) = address(this).call(batches[i]);\r\n\r\n      if (revertOnFailure) {\r\n        require(\r\n          succeeded,\r\n          \"Gateway: batch reverted\"\r\n        );\r\n      } else if (succeeded && !anySucceeded) {\r\n        anySucceeded = true;\r\n      }\r\n\r\n      emit BatchDelegated(\r\n        msg.sender,\r\n        batches[i],\r\n        succeeded\r\n      );\r\n    }\r\n\r\n    if (!anySucceeded) {\r\n      revert(\"Gateway: all batches reverted\");\r\n    }\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates multiple guarded batches\r\n   * @dev It will revert when all batches fail\r\n   * @param batches array of batches\r\n   * @param revertOnFailure reverts on any error\r\n   */\r\n  function delegateBatchesGuarded(\r\n    bytes[] memory batches,\r\n    bool revertOnFailure\r\n  )\r\n    public\r\n    onlyGuardian\r\n  {\r\n    delegateBatches(batches, revertOnFailure);\r\n  }\r\n\r\n  // public functions (views)\r\n\r\n  /**\r\n   * @notice Hashes `DelegatedBatch` message payload\r\n   * @param delegatedBatch struct\r\n   * @return hash\r\n   */\r\n  function hashDelegatedBatch(\r\n    DelegatedBatch memory delegatedBatch\r\n  )\r\n    public\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashDelegatedBatch(\r\n      delegatedBatch.account,\r\n      delegatedBatch.nonce,\r\n      delegatedBatch.to,\r\n      delegatedBatch.data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Hashes `DelegatedBatchWithGasPrice` message payload\r\n   * @param delegatedBatch struct\r\n   * @return hash\r\n   */\r\n  function hashDelegatedBatchWithGasPrice(\r\n    DelegatedBatchWithGasPrice memory delegatedBatch\r\n  )\r\n    public\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashDelegatedBatchWithGasPrice(\r\n      delegatedBatch.account,\r\n      delegatedBatch.nonce,\r\n      delegatedBatch.to,\r\n      delegatedBatch.data,\r\n      delegatedBatch.gasPrice\r\n    );\r\n  }\r\n\r\n  // external functions (views)\r\n\r\n  /**\r\n   * @notice Gets next account nonce\r\n   * @param account account address\r\n   * @return next nonce\r\n   */\r\n  function getAccountNextNonce(\r\n    address account\r\n  )\r\n    external\r\n    view\r\n    returns (uint256)\r\n  {\r\n    return accountNonce[account].add(1);\r\n  }\r\n\r\n  // private functions\r\n\r\n  function _sendBatch(\r\n    address account,\r\n    address sender,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    private\r\n  {\r\n    require(\r\n      account != address(0),\r\n      \"Gateway: cannot send from 0x0 account\"\r\n    );\r\n    require(\r\n      to.length > 0,\r\n      \"Gateway: cannot send empty batch\"\r\n    );\r\n    require(\r\n      data.length == to.length,\r\n      \"Gateway: invalid batch\"\r\n    );\r\n\r\n    if (account != sender) {\r\n      require(\r\n        personalAccountRegistry.verifyAccountOwner(account, sender) ||\r\n        externalAccountRegistry.verifyAccountOwner(account, sender),\r\n        \"Gateway: sender is not the account owner\"\r\n      );\r\n    }\r\n\r\n    bool succeeded;\r\n\r\n    for (uint256 i = 0; i < data.length; i++) {\r\n      require(\r\n        to[i] != address(0),\r\n        \"Gateway: cannot send to 0x0\"\r\n      );\r\n\r\n      // solhint-disable-next-line avoid-low-level-calls\r\n      (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\r\n\r\n      require(\r\n        succeeded,\r\n        \"Gateway: batch transaction reverted\"\r\n      );\r\n    }\r\n  }\r\n\r\n  // private functions (views)\r\n\r\n  function _hashDelegatedBatch(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    private\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH, abi.encodePacked(\r\n      account,\r\n      nonce,\r\n      to,\r\n      _concatBytes(data)\r\n    ));\r\n  }\r\n\r\n  function _hashDelegatedBatchWithGasPrice(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    uint256 gasPrice\r\n  )\r\n    private\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE, abi.encodePacked(\r\n      account,\r\n      nonce,\r\n      to,\r\n      _concatBytes(data),\r\n      gasPrice\r\n    ));\r\n  }\r\n\r\n// private functions (pure)\r\n\r\n  function _concatBytes(bytes[] memory data)\r\n    private\r\n    pure\r\n    returns (bytes memory)\r\n  {\r\n    bytes memory result;\r\n    uint dataLen = data.length;\r\n\r\n    for (uint i = 0 ; i < dataLen ; i++) {\r\n      result = abi.encodePacked(result, data[i]);\r\n    }\r\n\r\n    return result;\r\n  }\r\n}\r\n"
    },
    "src/gateway/Gateway.sol": {
      "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.12;\r\npragma experimental ABIEncoderV2;\r\n\r\nimport \"../common/libs/ECDSALib.sol\";\r\nimport \"../common/libs/SafeMathLib.sol\";\r\nimport \"../common/lifecycle/Initializable.sol\";\r\nimport \"../common/signature/SignatureValidator.sol\";\r\nimport \"../external/ExternalAccountRegistry.sol\";\r\nimport \"../personal/PersonalAccountRegistry.sol\";\r\n\r\n\r\n/**\r\n * @title Gateway\r\n *\r\n * @notice GSN replacement\r\n *\r\n * @author Stanisław Głogowski <stan@pillarproject.io>\r\n */\r\ncontract Gateway is Initializable, SignatureValidator {\r\n  using ECDSALib for bytes32;\r\n  using SafeMathLib for uint256;\r\n\r\n  struct DelegatedBatch {\r\n    address account;\r\n    uint256 nonce;\r\n    address[] to;\r\n    bytes[] data;\r\n  }\r\n\r\n  struct DelegatedBatchWithGasPrice {\r\n    address account;\r\n    uint256 nonce;\r\n    address[] to;\r\n    bytes[] data;\r\n    uint256 gasPrice;\r\n  }\r\n\r\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH = keccak256(\r\n    \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\r\n  );\r\n\r\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE = keccak256(\r\n    \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\r\n  );\r\n\r\n  ExternalAccountRegistry public externalAccountRegistry;\r\n  PersonalAccountRegistry public personalAccountRegistry;\r\n\r\n  mapping(address => uint256) private accountNonce;\r\n\r\n  // events\r\n\r\n  /**\r\n   * @dev Emitted when the single batch is delegated\r\n   * @param sender sender address\r\n   * @param batch batch\r\n   * @param succeeded if succeeded\r\n   */\r\n  event BatchDelegated(\r\n    address sender,\r\n    bytes batch,\r\n    bool succeeded\r\n  );\r\n\r\n  /**\r\n   * @dev Public constructor\r\n   */\r\n  constructor() public Initializable() SignatureValidator() {}\r\n\r\n  // external functions\r\n\r\n  /**\r\n   * @notice Initializes `Gateway` contract\r\n   * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\r\n   * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\r\n   */\r\n  function initialize(\r\n    ExternalAccountRegistry externalAccountRegistry_,\r\n    PersonalAccountRegistry personalAccountRegistry_\r\n  )\r\n    external\r\n    onlyInitializer\r\n  {\r\n    externalAccountRegistry = externalAccountRegistry_;\r\n    personalAccountRegistry = personalAccountRegistry_;\r\n  }\r\n\r\n  // public functions\r\n\r\n  /**\r\n   * @notice Sends batch\r\n   * @dev `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `msg.sender`\r\n   * `_getContextSender` will return `msg.sender`\r\n   *\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   */\r\n  function sendBatch(\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    public\r\n  {\r\n    _sendBatch(\r\n      msg.sender,\r\n      msg.sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Sends batch from the account\r\n   * @dev `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return `msg.sender`\r\n   *\r\n   * @param account account address\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   */\r\n  function sendBatchFromAccount(\r\n    address account,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    public\r\n  {\r\n    _sendBatch(\r\n      account,\r\n      msg.sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates batch from the account\r\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\r\n   *\r\n   * `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return recovered address from `senderSignature` arg\r\n   *\r\n   * @param account account address\r\n   * @param nonce next account nonce\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   * @param senderSignature sender signature\r\n   */\r\n  function delegateBatch(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    bytes memory senderSignature\r\n  )\r\n    public\r\n  {\r\n    require(\r\n      nonce > accountNonce[account],\r\n      \"Gateway: nonce is lower than current account nonce\"\r\n    );\r\n\r\n    address sender = _hashDelegatedBatch(\r\n      account,\r\n      nonce,\r\n      to,\r\n      data\r\n    ).recoverAddress(senderSignature);\r\n\r\n    accountNonce[account] = nonce;\r\n\r\n    _sendBatch(\r\n      account,\r\n      sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates batch from the account (with gas price)\r\n   *\r\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\r\n   *\r\n   * `GatewayRecipient` context api:\r\n   * `_getContextAccount` will return `account` arg\r\n   * `_getContextSender` will return recovered address from `senderSignature` arg\r\n   *\r\n   * @param account account address\r\n   * @param nonce next account nonce\r\n   * @param to array of batch recipients contracts\r\n   * @param data array of batch data\r\n   * @param senderSignature sender signature\r\n   */\r\n  function delegateBatchWithGasPrice(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    bytes memory senderSignature\r\n  )\r\n    public\r\n  {\r\n    require(\r\n      nonce > accountNonce[account],\r\n      \"Gateway: nonce is lower than current account nonce\"\r\n    );\r\n\r\n    address sender = _hashDelegatedBatchWithGasPrice(\r\n      account,\r\n      nonce,\r\n      to,\r\n      data,\r\n      tx.gasprice\r\n    ).recoverAddress(senderSignature);\r\n\r\n    accountNonce[account] = nonce;\r\n\r\n    _sendBatch(\r\n      account,\r\n      sender,\r\n      to,\r\n      data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Delegates multiple batches\r\n   * @dev It will revert when all batches fail\r\n   * @param batches array of batches\r\n   * @param revertOnFailure reverts on any error\r\n   */\r\n  function delegateBatches(\r\n    bytes[] memory batches,\r\n    bool revertOnFailure\r\n  )\r\n    public\r\n  {\r\n    require(\r\n      batches.length > 0,\r\n      \"Gateway: cannot delegate empty batches\"\r\n    );\r\n\r\n    bool anySucceeded;\r\n\r\n    for (uint256 i = 0; i < batches.length; i++) {\r\n      // solhint-disable-next-line avoid-low-level-calls\r\n      (bool succeeded,) = address(this).call(batches[i]);\r\n\r\n      if (revertOnFailure) {\r\n        require(\r\n          succeeded,\r\n          \"Gateway: batch reverted\"\r\n        );\r\n      } else if (succeeded && !anySucceeded) {\r\n        anySucceeded = true;\r\n      }\r\n\r\n      emit BatchDelegated(\r\n        msg.sender,\r\n        batches[i],\r\n        succeeded\r\n      );\r\n    }\r\n\r\n    if (!anySucceeded) {\r\n      revert(\"Gateway: all batches reverted\");\r\n    }\r\n  }\r\n\r\n  // public functions (views)\r\n\r\n  /**\r\n   * @notice Hashes `DelegatedBatch` message payload\r\n   * @param delegatedBatch struct\r\n   * @return hash\r\n   */\r\n  function hashDelegatedBatch(\r\n    DelegatedBatch memory delegatedBatch\r\n  )\r\n    public\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashDelegatedBatch(\r\n      delegatedBatch.account,\r\n      delegatedBatch.nonce,\r\n      delegatedBatch.to,\r\n      delegatedBatch.data\r\n    );\r\n  }\r\n\r\n  /**\r\n   * @notice Hashes `DelegatedBatchWithGasPrice` message payload\r\n   * @param delegatedBatch struct\r\n   * @return hash\r\n   */\r\n  function hashDelegatedBatchWithGasPrice(\r\n    DelegatedBatchWithGasPrice memory delegatedBatch\r\n  )\r\n    public\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashDelegatedBatchWithGasPrice(\r\n      delegatedBatch.account,\r\n      delegatedBatch.nonce,\r\n      delegatedBatch.to,\r\n      delegatedBatch.data,\r\n      delegatedBatch.gasPrice\r\n    );\r\n  }\r\n\r\n  // external functions (views)\r\n\r\n  /**\r\n   * @notice Gets next account nonce\r\n   * @param account account address\r\n   * @return next nonce\r\n   */\r\n  function getAccountNextNonce(\r\n    address account\r\n  )\r\n    external\r\n    view\r\n    returns (uint256)\r\n  {\r\n    return accountNonce[account].add(1);\r\n  }\r\n\r\n  // private functions\r\n\r\n  function _sendBatch(\r\n    address account,\r\n    address sender,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    private\r\n  {\r\n    require(\r\n      account != address(0),\r\n      \"Gateway: cannot send from 0x0 account\"\r\n    );\r\n    require(\r\n      to.length > 0,\r\n      \"Gateway: cannot send empty batch\"\r\n    );\r\n    require(\r\n      data.length == to.length,\r\n      \"Gateway: invalid batch\"\r\n    );\r\n\r\n    if (account != sender) {\r\n      require(\r\n        personalAccountRegistry.verifyAccountOwner(account, sender) ||\r\n        externalAccountRegistry.verifyAccountOwner(account, sender),\r\n        \"Gateway: sender is not the account owner\"\r\n      );\r\n    }\r\n\r\n    bool succeeded;\r\n\r\n    for (uint256 i = 0; i < data.length; i++) {\r\n      require(\r\n        to[i] != address(0),\r\n        \"Gateway: cannot send to 0x0\"\r\n      );\r\n\r\n      // solhint-disable-next-line avoid-low-level-calls\r\n      (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\r\n\r\n      require(\r\n        succeeded,\r\n        \"Gateway: batch transaction reverted\"\r\n      );\r\n    }\r\n  }\r\n\r\n  // private functions (views)\r\n\r\n  function _hashDelegatedBatch(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data\r\n  )\r\n    private\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH, abi.encodePacked(\r\n      account,\r\n      nonce,\r\n      to,\r\n      _concatBytes(data)\r\n    ));\r\n  }\r\n\r\n  function _hashDelegatedBatchWithGasPrice(\r\n    address account,\r\n    uint256 nonce,\r\n    address[] memory to,\r\n    bytes[] memory data,\r\n    uint256 gasPrice\r\n  )\r\n    private\r\n    view\r\n    returns (bytes32)\r\n  {\r\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE, abi.encodePacked(\r\n      account,\r\n      nonce,\r\n      to,\r\n      _concatBytes(data),\r\n      gasPrice\r\n    ));\r\n  }\r\n\r\n// private functions (pure)\r\n\r\n  function _concatBytes(bytes[] memory data)\r\n    private\r\n    pure\r\n    returns (bytes memory)\r\n  {\r\n    bytes memory result;\r\n    uint dataLen = data.length;\r\n\r\n    for (uint i = 0 ; i < dataLen ; i++) {\r\n      result = abi.encodePacked(result, data[i]);\r\n    }\r\n\r\n    return result;\r\n  }\r\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/signature/SignatureValidator.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\nimport \"./resolvers/ENSAddressResolver.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./resolvers/ENSPubKeyResolver.sol\";\nimport \"./resolvers/ENSTextResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n\n/**\n * @title ENS controller\n *\n * @notice ENS subnode registrar\n *\n * @dev The process of adding root node consists of 3 steps:\n * 1. `submitNode` - should be called from ENS node owner,\n * 2. Change ENS node owner in ENS registry to ENS controller,\n * 3. `verifyNode` - should be called from previous ENS node owner,\n *\n * To register sub node, `msg.sender` need to send valid signature from one of guardian key.\n * Once registration is complete `msg.sender` becoming both node owner and `addr` record value.\n *\n * After registration sub node cannot be replaced.\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract ENSController is Guarded, Initializable, SignatureValidator, GatewayRecipient, ENSAddressResolver, ENSNameResolver, ENSPubKeyResolver, ENSTextResolver {\n  struct SubNodeRegistration {\n    address account;\n    bytes32 node;\n    bytes32 label;\n  }\n\n  bytes4 private constant INTERFACE_META_ID = bytes4(keccak256(abi.encodePacked(\"supportsInterface(bytes4)\")));\n\n  bytes32 private constant HASH_PREFIX_SUB_NODE_REGISTRATION = keccak256(\n    \"SubNodeRegistration(address account,bytes32 node,bytes32 label)\"\n  );\n\n  ENSRegistry public registry;\n\n  mapping(bytes32 => address) public nodeOwners;\n\n  // events\n\n  /**\n   * @dev Emitted when 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() SignatureValidator() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `ENSController` contract\n   * @param registry_ ENS registry address\n   * @param gateway_ gateway address\n   */\n  function initialize(\n    ENSRegistry registry_,\n    address[] calldata guardians_,\n    address gateway_\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\n  /**\n   * @notice Sets registry\n   * @param registry_ registry address\n   */\n  function setRegistry(\n    ENSRegistry registry_\n  )\n    external\n    onlyGuardian\n  {\n    require(\n      address(registry_) != address(0),\n      \"ENSController: cannot set 0x0 registry\"\n    );\n\n    require(\n      registry_ != registry,\n      \"ENSController: registry already set\"\n    );\n\n    registry = registry_;\n\n    emit RegistryChanged(\n      address(registry)\n    );\n  }\n\n  /**\n   * @notice Submits node\n   * @dev Should be called from the current ENS node owner\n   * @param node node name hash\n   */\n  function submitNode(\n    bytes32 node\n  )\n    external\n  {\n    address owner = _getContextAccount();\n\n    require(\n      _addr(node) == address(0),\n      \"ENSController: node already exists\"\n    );\n\n    require(\n      nodeOwners[node] == address(0),\n      \"ENSController: node already submitted\"\n    );\n\n    require(\n      registry.owner(node) == owner,\n      \"ENSController: invalid ens node owner\"\n    );\n\n    nodeOwners[node] = owner;\n\n    emit NodeSubmitted(node, owner);\n  }\n\n  /**\n   * @notice Verifies node\n   * @dev Should be called from the previous ENS node owner\n   * @param node node name hash\n   */\n  function verifyNode(\n    bytes32 node\n  )\n    external\n  {\n    address owner = _getContextAccount();\n\n    require(\n      _addr(node) == address(0),\n      \"ENSController: node already exists\"\n    );\n\n    require(\n      nodeOwners[node] == owner,\n      \"ENSController: invalid node owner\"\n    );\n\n    require(\n      registry.owner(node) == address(this),\n      \"ENSController: invalid ens node owner\"\n    );\n\n    _setAddr(node, address(this));\n\n    registry.setResolver(node, address(this));\n\n    emit NodeVerified(node);\n  }\n\n  /**\n   * @notice Releases node\n   * @dev Should be called from the previous ENS node owner\n   * @param node node name hash\n   */\n  function releaseNode(\n    bytes32 node\n  )\n    external\n  {\n    address owner = _getContextAccount();\n\n    require(\n      _addr(node) == address(this),\n      \"ENSController: node doesn't exist\"\n    );\n\n    require(\n      nodeOwners[node] == owner,\n      \"ENSController: invalid node owner\"\n    );\n\n    registry.setOwner(node, owner);\n\n    delete nodeOwners[node];\n\n    emit NodeReleased(node, owner);\n  }\n\n  /**\n   * @notice Sync address\n   * @param node node name hash\n   */\n  function syncAddr(\n    bytes32 node\n  )\n    external\n  {\n    address account = _getContextAccount();\n\n    require(\n      account == registry.owner(node),\n      \"ENSController: caller is not the node owner\"\n    );\n\n    require(\n      registry.resolver(node) == address(this),\n      \"ENSController: invalid node resolver\"\n    );\n\n    require(\n      _addr(node) == address(0),\n      \"ENSController: node already in sync\"\n    );\n\n    _setAddr(node, account);\n  }\n\n  /**\n   * @notice Registers sub node\n   * @param node node name hash\n   * @param label label hash\n   * @param guardianSignature guardian signature\n   */\n  function registerSubNode(\n    bytes32 node,\n    bytes32 label,\n    bytes calldata guardianSignature\n  )\n    external\n  {\n    address account = _getContextAccount();\n\n    bytes32 messageHash = _hashSubNodeRegistration(\n      account,\n      node,\n      label\n    );\n\n    require(\n      _verifyGuardianSignature(messageHash, guardianSignature),\n      \"ENSController: invalid guardian signature\"\n    );\n\n    bytes32 subNode = keccak256(\n      abi.encodePacked(\n        node,\n        label\n      )\n    );\n\n    require(\n      _addr(node) == address(this),\n      \"ENSController: invalid node\"\n    );\n\n    require(\n      _addr(subNode) == address(0),\n      \"ENSController: label already taken\"\n    );\n\n    registry.setSubnodeRecord(node, label, address(this), address(this), 0);\n    registry.setOwner(subNode, account);\n\n    _setAddr(subNode, account);\n  }\n\n  // external functions (pure)\n  function supportsInterface(\n    bytes4 interfaceID\n  )\n    external\n    pure\n    returns(bool)\n  {\n    return interfaceID == INTERFACE_META_ID ||\n    interfaceID == INTERFACE_ADDR_ID ||\n    interfaceID == INTERFACE_ADDRESS_ID ||\n    interfaceID == INTERFACE_NAME_ID ||\n    interfaceID == INTERFACE_PUB_KEY_ID ||\n    interfaceID == INTERFACE_TEXT_ID;\n  }\n\n  // public functions (views)\n\n  /**\n   * @notice Hashes `SubNodeRegistration` message payload\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 _hashSubNodeRegistration(\n      subNodeRegistration.account,\n      subNodeRegistration.node,\n      subNodeRegistration.label\n    );\n  }\n\n  // internal functions (views)\n\n  function _isNodeOwner(\n    bytes32 node\n  )\n    internal\n    override\n    view\n    returns (bool)\n  {\n    return registry.owner(node) == _getContextAccount();\n  }\n\n  // private functions (views)\n\n  function _hashSubNodeRegistration(\n    address account,\n    bytes32 node,\n    bytes32 label\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_SUB_NODE_REGISTRATION, abi.encodePacked(\n      account,\n      node,\n      label\n    ));\n  }\n}\n"
    },
    "src/ens/resolvers/ENSAddressResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract address resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/AddrResolver.sol\n */\nabstract contract ENSAddressResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_ADDR_ID = bytes4(keccak256(abi.encodePacked(\"addr(bytes32)\")));\n  bytes4 internal constant INTERFACE_ADDRESS_ID = bytes4(keccak256(abi.encodePacked(\"addr(bytes32,uint)\")));\n\n  uint internal constant COIN_TYPE_ETH = 60;\n\n  mapping(bytes32 => mapping(uint => bytes)) internal resolverAddresses;\n\n  // events\n\n  event AddrChanged(\n    bytes32 indexed node,\n    address addr\n  );\n\n  event AddressChanged(\n    bytes32 indexed node,\n    uint coinType,\n    bytes newAddress\n  );\n\n  // external functions\n\n  function setAddr(\n    bytes32 node,\n    address addr_\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    _setAddr(node, addr_);\n  }\n\n  function setAddr(\n    bytes32 node,\n    uint coinType,\n    bytes memory addr_\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    _setAddr(node, coinType, addr_);\n  }\n\n  // external functions (views)\n\n  function addr(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    return _addr(node);\n  }\n\n  function addr(\n    bytes32 node,\n    uint coinType\n  )\n    external\n    view\n    returns (bytes memory)\n  {\n    return resolverAddresses[node][coinType];\n  }\n\n  // internal functions\n\n  function _setAddr(\n    bytes32 node,\n    address addr_\n  )\n    internal\n  {\n    _setAddr(node, COIN_TYPE_ETH, _addressToBytes(addr_));\n  }\n\n  function _setAddr(\n    bytes32 node,\n    uint coinType,\n    bytes memory addr_\n  )\n    internal\n  {\n    emit AddressChanged(node, coinType, addr_);\n\n    if(coinType == COIN_TYPE_ETH) {\n      emit AddrChanged(node, _bytesToAddress(addr_));\n    }\n\n    resolverAddresses[node][coinType] = addr_;\n  }\n\n  // internal functions (views)\n\n  function _addr(\n    bytes32 node\n  )\n    internal\n    view\n    returns (address)\n  {\n    address result;\n\n    bytes memory addr_ = resolverAddresses[node][COIN_TYPE_ETH];\n\n    if (addr_.length > 0) {\n      result = _bytesToAddress(addr_);\n    }\n\n    return result;\n  }\n\n  // private function (pure)\n\n  function _bytesToAddress(\n    bytes memory data\n  )\n    private\n    pure\n    returns(address payable)\n  {\n    address payable result;\n\n    require(data.length == 20);\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      result := div(mload(add(data, 32)), exp(256, 12))\n    }\n\n    return result;\n  }\n\n  function _addressToBytes(\n    address addr_\n  )\n    private\n    pure\n    returns(bytes memory)\n  {\n    bytes memory result = new bytes(20);\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      mstore(add(result, 32), mul(addr_, exp(256, 12)))\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/ens/resolvers/ENSNameResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract name resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/NameResolver.sol\n */\nabstract contract ENSNameResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_NAME_ID = bytes4(keccak256(abi.encodePacked(\"name(bytes32)\")));\n\n  mapping(bytes32 => string) internal resolverNames;\n\n  // events\n\n  event NameChanged(\n    bytes32 indexed node,\n    string name\n  );\n\n  // external functions\n\n  function setName(\n    bytes32 node,\n    string calldata name\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    resolverNames[node] = name;\n\n    emit NameChanged(node, name);\n  }\n\n  // external functions (views)\n\n  function name(\n    bytes32 node\n  )\n    external\n    view\n    returns (string memory)\n  {\n    return resolverNames[node];\n  }\n}\n"
    },
    "src/ens/resolvers/ENSPubKeyResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract pub key resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/PubkeyResolver.sol\n */\nabstract contract ENSPubKeyResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_PUB_KEY_ID = bytes4(keccak256(abi.encodePacked(\"pubkey(bytes32)\")));\n\n  struct PubKey {\n    bytes32 x;\n    bytes32 y;\n  }\n\n  mapping(bytes32 => PubKey) internal resolverPubKeys;\n\n  // events\n\n  event PubkeyChanged(\n    bytes32 indexed node,\n    bytes32 x,\n    bytes32 y\n  );\n\n  // external functions (views)\n\n  function setPubkey(\n    bytes32 node,\n    bytes32 x,\n    bytes32 y\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    resolverPubKeys[node] = PubKey(x, y);\n\n    emit PubkeyChanged(node, x, y);\n  }\n\n  // external functions (views)\n\n  function pubkey(\n    bytes32 node\n  )\n    external\n    view\n    returns (bytes32 x, bytes32 y)\n  {\n    return (resolverPubKeys[node].x, resolverPubKeys[node].y);\n  }\n}\n"
    },
    "src/ens/resolvers/ENSTextResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract text resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/TextResolver.sol\n */\nabstract contract ENSTextResolver is ENSAbstractResolver {\n  bytes4 internal constant INTERFACE_TEXT_ID = bytes4(keccak256(abi.encodePacked(\"text(bytes32,string)\")));\n\n  mapping(bytes32 => mapping(string => string)) internal resolverTexts;\n\n  // events\n\n  event TextChanged(\n    bytes32 indexed node,\n    string indexed indexedKey,\n    string key\n  );\n\n  // external functions (views)\n\n  function setText(\n    bytes32 node,\n    string calldata key,\n    string calldata value\n  )\n    external\n    onlyNodeOwner(node)\n  {\n    resolverTexts[node][key] = value;\n\n    emit TextChanged(node, key, key);\n  }\n\n  // external functions (views)\n\n  function text(\n    bytes32 node,\n    string calldata key\n  )\n    external\n    view\n    returns (string memory)\n  {\n    return resolverTexts[node][key];\n  }\n}\n"
    },
    "src/ens/ENSRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ENS registry\n *\n * @dev Base on https://github.com/ensdomains/ens/blob/ff0f41747c05f1598973b0fe7ad0d9e09565dfcd/contracts/ENSRegistry.sol\n */\ncontract ENSRegistry {\n  struct Record {\n    address owner;\n    address resolver;\n    uint64 ttl;\n  }\n\n  mapping (bytes32 => Record) private records;\n  mapping (address => mapping(address => bool)) private operators;\n\n  // events\n\n  event NewOwner(\n    bytes32 indexed node,\n    bytes32 indexed label,\n    address owner\n  );\n\n  event Transfer(\n    bytes32 indexed node,\n    address owner\n  );\n\n  event NewResolver(\n    bytes32 indexed node,\n    address resolver\n  );\n\n  event NewTTL(\n    bytes32 indexed node,\n    uint64 ttl\n  );\n\n  event ApprovalForAll(\n    address indexed owner,\n    address indexed operator,\n    bool approved\n  );\n\n  // modifiers\n\n  modifier authorised(\n    bytes32 node\n  )\n  {\n    address owner = records[node].owner;\n\n    require(\n      owner == msg.sender || operators[owner][msg.sender],\n      \"ENSRegistry: reverted by authorised modifier\"\n    );\n\n    _;\n  }\n\n  /**\n   * @dev Public constructor\n   */\n  constructor()\n    public\n  {\n    // solhint-disable-next-line avoid-tx-origin\n    records[0x0].owner = tx.origin;\n  }\n\n  // external functions\n\n  function setRecord(\n    bytes32 node,\n    address owner_,\n    address resolver_,\n    uint64 ttl_\n  )\n    external\n  {\n    setOwner(node, owner_);\n\n    _setResolverAndTTL(node, resolver_, ttl_);\n  }\n\n  function setTTL(\n    bytes32 node,\n    uint64 ttl_\n  )\n    external\n    authorised(node)\n  {\n    records[node].ttl = ttl_;\n\n    emit NewTTL(node, ttl_);\n  }\n\n  function setSubnodeRecord(\n    bytes32 node,\n    bytes32 label,\n    address owner_,\n    address resolver_,\n    uint64 ttl_\n  )\n    external\n  {\n    bytes32 subNode = setSubnodeOwner(node, label, owner_);\n\n    _setResolverAndTTL(subNode, resolver_, ttl_);\n  }\n\n  function setApprovalForAll(\n    address operator,\n    bool approved\n  )\n    external\n  {\n    operators[msg.sender][operator] = approved;\n\n    emit ApprovalForAll(\n      msg.sender,\n      operator,\n      approved\n    );\n  }\n\n  // external functions (views)\n\n  function owner(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    address addr = records[node].owner;\n\n    if (addr == address(this)) {\n      return address(0x0);\n    }\n\n    return addr;\n  }\n\n  function resolver(\n    bytes32 node\n  )\n    external\n    view\n    returns (address)\n  {\n    return records[node].resolver;\n  }\n\n  function ttl(\n    bytes32 node\n  )\n    external\n    view\n    returns (uint64)\n  {\n    return records[node].ttl;\n  }\n\n  function recordExists(\n    bytes32 node\n  )\n    external\n    view\n    returns (bool)\n  {\n    return records[node].owner != address(0x0);\n  }\n\n  function isApprovedForAll(\n    address owner_,\n    address operator\n  )\n    external\n    view\n    returns (bool)\n  {\n    return operators[owner_][operator];\n  }\n\n  // public functions\n\n  function setOwner(\n    bytes32 node,\n    address owner_\n  )\n    public\n    authorised(node)\n  {\n    records[node].owner = owner_;\n\n    emit Transfer(node, owner_);\n  }\n\n  function setResolver(\n    bytes32 node,\n    address resolver_\n  )\n    public\n    authorised(node)\n  {\n    records[node].resolver = resolver_;\n\n    emit NewResolver(node, resolver_);\n  }\n\n  function setSubnodeOwner(\n    bytes32 node,\n    bytes32 label,\n    address owner_\n  )\n    public\n    authorised(node)\n    returns(bytes32)\n  {\n    bytes32 subNode = keccak256(abi.encodePacked(node, label));\n\n    records[subNode].owner = owner_;\n\n    emit NewOwner(node, label, owner_);\n\n    return subNode;\n  }\n\n  // private functions\n\n  function _setResolverAndTTL(\n    bytes32 node,\n    address resolver_,\n    uint64 ttl_\n  )\n    private\n  {\n    if (resolver_ != records[node].resolver) {\n      records[node].resolver = resolver_;\n\n      emit NewResolver(node, resolver_);\n    }\n\n    if (ttl_ != records[node].ttl) {\n      records[node].ttl = ttl_;\n\n      emit NewTTL(node, ttl_);\n    }\n  }\n}\n"
    },
    "src/ens/resolvers/ENSAbstractResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ENS abstract resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/ResolverBase.sol\n */\nabstract contract ENSAbstractResolver {\n  // modifiers\n\n  modifier onlyNodeOwner(bytes32 node)\n  {\n    require(\n      _isNodeOwner(node),\n      \"ENSAbstractResolver: reverted by onlyNodeOwner modifier\"\n    );\n\n    _;\n  }\n\n  // internal functions (views)\n\n  function _isNodeOwner(\n    bytes32 node\n  )\n    internal\n    virtual\n    view\n    returns (bool);\n}\n"
    },
    "src/ens/ENSReverseRegistrar.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/AddressLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n/**\n * @title ENS reverse registrar\n *\n * @dev Base on https://github.com/ensdomains/ens/blob/ff0f41747c05f1598973b0fe7ad0d9e09565dfcd/contracts/ReverseRegistrar.sol\n */\ncontract ENSReverseRegistrar is Initializable {\n  using AddressLib for address;\n\n  // namehash('addr.reverse')\n  bytes32 public constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;\n\n  ENSRegistry public registry;\n  ENSNameResolver public resolver;\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `ENSReverseRegistrar` contract\n   * @param registry_ ENS registry address\n   * @param resolver_ ENS name resolver address\n   */\n  function initialize(\n    ENSRegistry registry_,\n    ENSNameResolver resolver_\n  )\n    external\n    onlyInitializer\n  {\n    registry = registry_;\n    resolver = resolver_;\n  }\n\n  // external functions\n\n  function claim(\n    address owner\n  )\n    public\n    returns (bytes32)\n  {\n    return _claimWithResolver(owner, address(0));\n  }\n\n  function claimWithResolver(\n    address owner,\n    address resolver_\n  )\n    public\n    returns (bytes32)\n  {\n    return _claimWithResolver(owner, resolver_);\n  }\n\n  function setName(\n    string memory name\n  )\n    public\n    returns (bytes32)\n  {\n    bytes32 node = _claimWithResolver(address(this), address(resolver));\n\n    resolver.setName(node, name);\n\n    return node;\n  }\n\n  // external functions (pure)\n\n  function node(\n    address addr_\n  )\n    external\n    pure\n    returns (bytes32)\n  {\n    return keccak256(abi.encodePacked(ADDR_REVERSE_NODE, addr_.toSha3Hash()));\n  }\n\n  // private functions\n\n  function _claimWithResolver(\n    address owner,\n    address resolver_\n  )\n    private\n    returns (bytes32)\n  {\n    bytes32 label = address(msg.sender).toSha3Hash();\n    bytes32 node_ = keccak256(abi.encodePacked(ADDR_REVERSE_NODE, label));\n    address currentOwner = registry.owner(node_);\n\n    if (resolver_ != address(0x0) && resolver_ != registry.resolver(node_)) {\n      if (currentOwner != address(this)) {\n        registry.setSubnodeOwner(ADDR_REVERSE_NODE, label, address(this));\n        currentOwner = address(this);\n      }\n\n      registry.setResolver(node_, resolver_);\n    }\n\n    // Update the owner if required\n    if (currentOwner != owner) {\n      registry.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);\n    }\n\n    return node_;\n  }\n}\n"
    },
    "src/common/libs/AddressLib.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Address library\n */\nlibrary AddressLib {\n  /**\n   * @notice Converts address into sha3 hash\n   * @param self address\n   * @return sha3 hash\n   */\n  function toSha3Hash(\n    address self\n  )\n    internal\n    pure\n    returns (bytes32)\n  {\n    bytes32 result;\n\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      let lookup := 0x3031323334353637383961626364656600000000000000000000000000000000\n\n      for { let i := 40 } gt(i, 0) { } {\n        i := sub(i, 1)\n        mstore8(i, byte(and(self, 0xf), lookup))\n        self := div(self, 0x10)\n        i := sub(i, 1)\n        mstore8(i, byte(and(self, 0xf), lookup))\n        self := div(self, 0x10)\n      }\n\n      result := keccak256(0, 40)\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/ens/ENSHelper.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"./resolvers/ENSAddressResolver.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n/**\n * @title ENS helper\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract ENSHelper is Initializable {\n  ENSRegistry public registry;\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `ENSLookupHelper` contract\n   * @param registry_ ENS registry address\n   */\n  function initialize(\n    ENSRegistry registry_\n  )\n    external\n    onlyInitializer\n  {\n    registry = registry_;\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Gets nodes addresses\n   * @param nodes array of nodes\n   * @return nodes addresses\n   */\n  function getAddresses(\n    bytes32[] memory nodes\n  )\n    external\n    view\n    returns (address[] memory)\n  {\n    uint nodesLen = nodes.length;\n    address[] memory result = new address[](nodesLen);\n\n    for (uint i = 0; i < nodesLen; i++) {\n      result[i] = _getAddress(nodes[i]);\n    }\n\n    return result;\n  }\n\n  /**\n   * @notice Gets nodes names\n   * @param nodes array of nodes\n   * @return nodes names\n   */\n  function getNames(\n    bytes32[] memory nodes\n  )\n    external\n    view\n    returns (string[] memory)\n  {\n    uint nodesLen = nodes.length;\n    string[] memory result = new string[](nodesLen);\n\n    for (uint i = 0; i < nodesLen; i++) {\n      result[i] = _getName(nodes[i]);\n    }\n\n    return result;\n  }\n\n  // private functions (views)\n\n  function _getAddress(\n    bytes32 node\n  )\n    private\n    view\n    returns (address)\n  {\n    address result;\n    address resolver = registry.resolver(node);\n\n    if (resolver != address(0)) {\n      try ENSAddressResolver(resolver).addr(node) returns (address addr) {\n        result = addr;\n      } catch {\n        //\n      }\n    }\n\n    return result;\n  }\n\n  function _getName(\n    bytes32 node\n  )\n    private\n    view\n    returns (string memory)\n  {\n    string memory result;\n    address resolver = registry.resolver(node);\n\n    if (resolver != address(0)) {\n      try ENSNameResolver(resolver).name(node) returns (string memory name) {\n        result = name;\n      } catch {\n        //\n      }\n    }\n\n    return result;\n  }\n}\n"
    },
    "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"
    }
  },
  "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"
        ]
      }
    }
  }
}