{
  "language": "Solidity",
  "sources": {
    "src/gateway/GatewayV2.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 \"../external/ExternalAccountRegistry.sol\";\nimport \"../personal/PersonalAccountRegistry.sol\";\n\n/**\n * @title Gateway V2 with guarded batching functions\n *\n * @notice GSN replacement\n *\n * @author Utkir Sobirov <sobirovutkir@gmail.io>\n */\ncontract GatewayV2 is Initializable, SignatureValidator, Guarded {\n  using ECDSALib for bytes32;\n  using SafeMathLib for uint256;\n\n  struct DelegatedBatch {\n    address account;\n    uint256 nonce;\n    address[] to;\n    bytes[] data;\n  }\n\n  struct DelegatedBatchWithGasPrice {\n    address account;\n    uint256 nonce;\n    address[] to;\n    bytes[] data;\n    uint256 gasPrice;\n  }\n\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH = keccak256(\n    \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\n  );\n\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE = keccak256(\n    \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\n  );\n\n  ExternalAccountRegistry public externalAccountRegistry;\n  PersonalAccountRegistry public personalAccountRegistry;\n\n  mapping(address => uint256) private accountNonce;\n\n  // events\n\n  /**\n   * @dev Emitted when the single batch is delegated\n   * @param sender sender address\n   * @param batch batch\n   * @param succeeded if succeeded\n   */\n  event BatchDelegated(\n    address sender,\n    bytes batch,\n    bool succeeded\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() SignatureValidator() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `Gateway` contract\n   * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\n   * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\n   */\n  function initialize(\n    ExternalAccountRegistry externalAccountRegistry_,\n    PersonalAccountRegistry personalAccountRegistry_\n  )\n    external\n    onlyInitializer\n  {\n    externalAccountRegistry = externalAccountRegistry_;\n    personalAccountRegistry = personalAccountRegistry_;\n\n    address[] memory guardians;\n    _initializeGuarded(guardians); // adds tx.origin to guardians list\n  }\n\n  // public functions\n\n  /**\n   * @notice Sends batch\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `msg.sender`\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatch(\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n  {\n    _sendBatch(\n      msg.sender,\n      msg.sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Sends guarded batch\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `msg.sender`\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatchGuarded(\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n    onlyGuardian\n  {\n    sendBatch(to, data);\n  }\n\n  /**\n   * @notice Sends batch from the account\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param account account address\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatchFromAccount(\n    address account,\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n  {\n    _sendBatch(\n      account,\n      msg.sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Sends guarded batch from the account\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param account account address\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatchFromAccountGuarded(\n    address account,\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n    onlyGuardian\n  {\n    sendBatchFromAccount(account, to, data);\n  }\n\n  /**\n   * @notice Delegates batch from the account\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatch(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n  {\n    require(\n      nonce > accountNonce[account],\n      \"Gateway: nonce is lower than current account nonce\"\n    );\n\n    address sender = _hashDelegatedBatch(\n      account,\n      nonce,\n      to,\n      data\n    ).recoverAddress(senderSignature);\n\n    accountNonce[account] = nonce;\n\n    _sendBatch(\n      account,\n      sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates guarded batch from the account\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatchGuarded(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n    onlyGuardian\n  {\n    delegateBatch(account, nonce, to, data, senderSignature);\n  }\n\n  /**\n   * @notice Delegates batch from the account (with gas price)\n   *\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatchWithGasPrice(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n  {\n    require(\n      nonce > accountNonce[account],\n      \"Gateway: nonce is lower than current account nonce\"\n    );\n\n    address sender = _hashDelegatedBatchWithGasPrice(\n      account,\n      nonce,\n      to,\n      data,\n      tx.gasprice\n    ).recoverAddress(senderSignature);\n\n    accountNonce[account] = nonce;\n\n    _sendBatch(\n      account,\n      sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates guarded batch from the account (with gas price)\n   *\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatchWithGasPriceGuarded(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n    onlyGuardian\n  {\n    delegateBatchWithGasPrice(account, nonce, to, data, senderSignature);\n  }\n\n  /**\n   * @notice Delegates multiple batches\n   * @dev It will revert when all batches fail\n   * @param batches array of batches\n   * @param revertOnFailure reverts on any error\n   */\n  function delegateBatches(\n    bytes[] memory batches,\n    bool revertOnFailure\n  )\n    public\n  {\n    require(\n      batches.length > 0,\n      \"Gateway: cannot delegate empty batches\"\n    );\n\n    bool anySucceeded;\n\n    for (uint256 i = 0; i < batches.length; i++) {\n      // solhint-disable-next-line avoid-low-level-calls\n      (bool succeeded,) = address(this).call(batches[i]);\n\n      if (revertOnFailure) {\n        require(\n          succeeded,\n          \"Gateway: batch reverted\"\n        );\n      } else if (succeeded && !anySucceeded) {\n        anySucceeded = true;\n      }\n\n      emit BatchDelegated(\n        msg.sender,\n        batches[i],\n        succeeded\n      );\n    }\n\n    if (!anySucceeded) {\n      revert(\"Gateway: all batches reverted\");\n    }\n  }\n\n  /**\n   * @notice Delegates multiple guarded batches\n   * @dev It will revert when all batches fail\n   * @param batches array of batches\n   * @param revertOnFailure reverts on any error\n   */\n  function delegateBatchesGuarded(\n    bytes[] memory batches,\n    bool revertOnFailure\n  )\n    public\n    onlyGuardian\n  {\n    delegateBatches(batches, revertOnFailure);\n  }\n\n  // public functions (views)\n\n  /**\n   * @notice Hashes `DelegatedBatch` message payload\n   * @param delegatedBatch struct\n   * @return hash\n   */\n  function hashDelegatedBatch(\n    DelegatedBatch memory delegatedBatch\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashDelegatedBatch(\n      delegatedBatch.account,\n      delegatedBatch.nonce,\n      delegatedBatch.to,\n      delegatedBatch.data\n    );\n  }\n\n  /**\n   * @notice Hashes `DelegatedBatchWithGasPrice` message payload\n   * @param delegatedBatch struct\n   * @return hash\n   */\n  function hashDelegatedBatchWithGasPrice(\n    DelegatedBatchWithGasPrice memory delegatedBatch\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashDelegatedBatchWithGasPrice(\n      delegatedBatch.account,\n      delegatedBatch.nonce,\n      delegatedBatch.to,\n      delegatedBatch.data,\n      delegatedBatch.gasPrice\n    );\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Gets next account nonce\n   * @param account account address\n   * @return next nonce\n   */\n  function getAccountNextNonce(\n    address account\n  )\n    external\n    view\n    returns (uint256)\n  {\n    return accountNonce[account].add(1);\n  }\n\n  // private functions\n\n  function _sendBatch(\n    address account,\n    address sender,\n    address[] memory to,\n    bytes[] memory data\n  )\n    private\n  {\n    require(\n      account != address(0),\n      \"Gateway: cannot send from 0x0 account\"\n    );\n    require(\n      to.length > 0,\n      \"Gateway: cannot send empty batch\"\n    );\n    require(\n      data.length == to.length,\n      \"Gateway: invalid batch\"\n    );\n\n    if (account != sender) {\n      require(\n        personalAccountRegistry.verifyAccountOwner(account, sender) ||\n        externalAccountRegistry.verifyAccountOwner(account, sender),\n        \"Gateway: sender is not the account owner\"\n      );\n    }\n\n    bool succeeded;\n\n    for (uint256 i = 0; i < data.length; i++) {\n      require(\n        to[i] != address(0),\n        \"Gateway: cannot send to 0x0\"\n      );\n\n      // solhint-disable-next-line avoid-low-level-calls\n      (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\n\n      require(\n        succeeded,\n        \"Gateway: batch transaction reverted\"\n      );\n    }\n  }\n\n  // private functions (views)\n\n  function _hashDelegatedBatch(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH, abi.encodePacked(\n      account,\n      nonce,\n      to,\n      _concatBytes(data)\n    ));\n  }\n\n  function _hashDelegatedBatchWithGasPrice(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    uint256 gasPrice\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE, abi.encodePacked(\n      account,\n      nonce,\n      to,\n      _concatBytes(data),\n      gasPrice\n    ));\n  }\n\n// private functions (pure)\n\n  function _concatBytes(bytes[] memory data)\n    private\n    pure\n    returns (bytes memory)\n  {\n    bytes memory result;\n    uint dataLen = data.length;\n\n    for (uint i = 0 ; i < dataLen ; i++) {\n      result = abi.encodePacked(result, data[i]);\n    }\n\n    return result;\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/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/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/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/gateway/GatewayRecipient.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/BytesLib.sol\";\n\n\n/**\n * @title Gateway recipient\n *\n * @notice Gateway target contract\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract GatewayRecipient {\n  using BytesLib for bytes;\n\n  address public gateway;\n\n  /**\n   * @dev internal constructor\n   */\n  constructor() internal {}\n\n  // internal functions\n\n  /**\n   * @notice Initializes `GatewayRecipient` contract\n   * @param gateway_ `Gateway` contract address\n   */\n  function _initializeGatewayRecipient(\n    address gateway_\n  )\n    internal\n  {\n    gateway = gateway_;\n  }\n\n  // internal functions (views)\n\n  /**\n   * @notice Gets gateway context account\n   * @return context account address\n   */\n  function _getContextAccount()\n    internal\n    view\n    returns (address)\n  {\n    return _getContextAddress(40);\n  }\n\n  /**\n   * @notice Gets gateway context sender\n   * @return context sender address\n   */\n  function _getContextSender()\n    internal\n    view\n    returns (address)\n  {\n    return _getContextAddress(20);\n  }\n\n  /**\n   * @notice Gets gateway context data\n   * @return context data\n   */\n  function _getContextData()\n    internal\n    view\n    returns (bytes calldata)\n  {\n    bytes calldata result;\n\n    if (_isGatewaySender()) {\n      result = msg.data[:msg.data.length - 40];\n    } else {\n      result = msg.data;\n    }\n\n    return result;\n  }\n\n  // private functions (views)\n\n  function _getContextAddress(\n    uint256 offset\n  )\n    private\n    view\n    returns (address)\n  {\n    address result = address(0);\n\n    if (_isGatewaySender()) {\n      uint from = msg.data.length - offset;\n      result = bytes(msg.data[from:from + 20]).toAddress();\n    } else {\n      result = msg.sender;\n    }\n\n    return result;\n  }\n\n  function _isGatewaySender()\n    private\n    view\n    returns (bool)\n  {\n    bool result;\n\n    if (msg.sender == gateway) {\n      require(\n        msg.data.length >= 44,\n        \"GatewayRecipient: invalid msg.data\"\n      );\n\n      result = true;\n    }\n\n    return result;\n  }\n}\n"
    },
    "src/common/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/gateway/Gateway.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/libs/ECDSALib.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/signature/SignatureValidator.sol\";\nimport \"../external/ExternalAccountRegistry.sol\";\nimport \"../personal/PersonalAccountRegistry.sol\";\n\n\n/**\n * @title Gateway\n *\n * @notice GSN replacement\n *\n * @author Stanisław Głogowski <stan@pillarproject.io>\n */\ncontract Gateway is Initializable, SignatureValidator {\n  using ECDSALib for bytes32;\n  using SafeMathLib for uint256;\n\n  struct DelegatedBatch {\n    address account;\n    uint256 nonce;\n    address[] to;\n    bytes[] data;\n  }\n\n  struct DelegatedBatchWithGasPrice {\n    address account;\n    uint256 nonce;\n    address[] to;\n    bytes[] data;\n    uint256 gasPrice;\n  }\n\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH = keccak256(\n    \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\n  );\n\n  bytes32 private constant HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE = keccak256(\n    \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\n  );\n\n  ExternalAccountRegistry public externalAccountRegistry;\n  PersonalAccountRegistry public personalAccountRegistry;\n\n  mapping(address => uint256) private accountNonce;\n\n  // events\n\n  /**\n   * @dev Emitted when the single batch is delegated\n   * @param sender sender address\n   * @param batch batch\n   * @param succeeded if succeeded\n   */\n  event BatchDelegated(\n    address sender,\n    bytes batch,\n    bool succeeded\n  );\n\n  /**\n   * @dev Public constructor\n   */\n  constructor() public Initializable() SignatureValidator() {}\n\n  // external functions\n\n  /**\n   * @notice Initializes `Gateway` contract\n   * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\n   * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\n   */\n  function initialize(\n    ExternalAccountRegistry externalAccountRegistry_,\n    PersonalAccountRegistry personalAccountRegistry_\n  )\n    external\n    onlyInitializer\n  {\n    externalAccountRegistry = externalAccountRegistry_;\n    personalAccountRegistry = personalAccountRegistry_;\n  }\n\n  // public functions\n\n  /**\n   * @notice Sends batch\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `msg.sender`\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatch(\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n  {\n    _sendBatch(\n      msg.sender,\n      msg.sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Sends batch from the account\n   * @dev `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return `msg.sender`\n   *\n   * @param account account address\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   */\n  function sendBatchFromAccount(\n    address account,\n    address[] memory to,\n    bytes[] memory data\n  )\n    public\n  {\n    _sendBatch(\n      account,\n      msg.sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates batch from the account\n   * @dev Use `hashDelegatedBatch` to create sender message payload.\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatch(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n  {\n    require(\n      nonce > accountNonce[account],\n      \"Gateway: nonce is lower than current account nonce\"\n    );\n\n    address sender = _hashDelegatedBatch(\n      account,\n      nonce,\n      to,\n      data\n    ).recoverAddress(senderSignature);\n\n    accountNonce[account] = nonce;\n\n    _sendBatch(\n      account,\n      sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates batch from the account (with gas price)\n   *\n   * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\n   *\n   * `GatewayRecipient` context api:\n   * `_getContextAccount` will return `account` arg\n   * `_getContextSender` will return recovered address from `senderSignature` arg\n   *\n   * @param account account address\n   * @param nonce next account nonce\n   * @param to array of batch recipients contracts\n   * @param data array of batch data\n   * @param senderSignature sender signature\n   */\n  function delegateBatchWithGasPrice(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    bytes memory senderSignature\n  )\n    public\n  {\n    require(\n      nonce > accountNonce[account],\n      \"Gateway: nonce is lower than current account nonce\"\n    );\n\n    address sender = _hashDelegatedBatchWithGasPrice(\n      account,\n      nonce,\n      to,\n      data,\n      tx.gasprice\n    ).recoverAddress(senderSignature);\n\n    accountNonce[account] = nonce;\n\n    _sendBatch(\n      account,\n      sender,\n      to,\n      data\n    );\n  }\n\n  /**\n   * @notice Delegates multiple batches\n   * @dev It will revert when all batches fail\n   * @param batches array of batches\n   * @param revertOnFailure reverts on any error\n   */\n  function delegateBatches(\n    bytes[] memory batches,\n    bool revertOnFailure\n  )\n    public\n  {\n    require(\n      batches.length > 0,\n      \"Gateway: cannot delegate empty batches\"\n    );\n\n    bool anySucceeded;\n\n    for (uint256 i = 0; i < batches.length; i++) {\n      // solhint-disable-next-line avoid-low-level-calls\n      (bool succeeded,) = address(this).call(batches[i]);\n\n      if (revertOnFailure) {\n        require(\n          succeeded,\n          \"Gateway: batch reverted\"\n        );\n      } else if (succeeded && !anySucceeded) {\n        anySucceeded = true;\n      }\n\n      emit BatchDelegated(\n        msg.sender,\n        batches[i],\n        succeeded\n      );\n    }\n\n    if (!anySucceeded) {\n      revert(\"Gateway: all batches reverted\");\n    }\n  }\n\n  // public functions (views)\n\n  /**\n   * @notice Hashes `DelegatedBatch` message payload\n   * @param delegatedBatch struct\n   * @return hash\n   */\n  function hashDelegatedBatch(\n    DelegatedBatch memory delegatedBatch\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashDelegatedBatch(\n      delegatedBatch.account,\n      delegatedBatch.nonce,\n      delegatedBatch.to,\n      delegatedBatch.data\n    );\n  }\n\n  /**\n   * @notice Hashes `DelegatedBatchWithGasPrice` message payload\n   * @param delegatedBatch struct\n   * @return hash\n   */\n  function hashDelegatedBatchWithGasPrice(\n    DelegatedBatchWithGasPrice memory delegatedBatch\n  )\n    public\n    view\n    returns (bytes32)\n  {\n    return _hashDelegatedBatchWithGasPrice(\n      delegatedBatch.account,\n      delegatedBatch.nonce,\n      delegatedBatch.to,\n      delegatedBatch.data,\n      delegatedBatch.gasPrice\n    );\n  }\n\n  // external functions (views)\n\n  /**\n   * @notice Gets next account nonce\n   * @param account account address\n   * @return next nonce\n   */\n  function getAccountNextNonce(\n    address account\n  )\n    external\n    view\n    returns (uint256)\n  {\n    return accountNonce[account].add(1);\n  }\n\n  // private functions\n\n  function _sendBatch(\n    address account,\n    address sender,\n    address[] memory to,\n    bytes[] memory data\n  )\n    private\n  {\n    require(\n      account != address(0),\n      \"Gateway: cannot send from 0x0 account\"\n    );\n    require(\n      to.length > 0,\n      \"Gateway: cannot send empty batch\"\n    );\n    require(\n      data.length == to.length,\n      \"Gateway: invalid batch\"\n    );\n\n    if (account != sender) {\n      require(\n        personalAccountRegistry.verifyAccountOwner(account, sender) ||\n        externalAccountRegistry.verifyAccountOwner(account, sender),\n        \"Gateway: sender is not the account owner\"\n      );\n    }\n\n    bool succeeded;\n\n    for (uint256 i = 0; i < data.length; i++) {\n      require(\n        to[i] != address(0),\n        \"Gateway: cannot send to 0x0\"\n      );\n\n      // solhint-disable-next-line avoid-low-level-calls\n      (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\n\n      require(\n        succeeded,\n        \"Gateway: batch transaction reverted\"\n      );\n    }\n  }\n\n  // private functions (views)\n\n  function _hashDelegatedBatch(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH, abi.encodePacked(\n      account,\n      nonce,\n      to,\n      _concatBytes(data)\n    ));\n  }\n\n  function _hashDelegatedBatchWithGasPrice(\n    address account,\n    uint256 nonce,\n    address[] memory to,\n    bytes[] memory data,\n    uint256 gasPrice\n  )\n    private\n    view\n    returns (bytes32)\n  {\n    return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE, abi.encodePacked(\n      account,\n      nonce,\n      to,\n      _concatBytes(data),\n      gasPrice\n    ));\n  }\n\n// private functions (pure)\n\n  function _concatBytes(bytes[] memory data)\n    private\n    pure\n    returns (bytes memory)\n  {\n    bytes memory result;\n    uint dataLen = data.length;\n\n    for (uint i = 0 ; i < dataLen ; i++) {\n      result = abi.encodePacked(result, data[i]);\n    }\n\n    return result;\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"
        ]
      }
    }
  }
}