diff --git a/DEPLOYMENTS.md b/DEPLOYMENTS.md index 94e76a6e..29f505c6 100644 --- a/DEPLOYMENTS.md +++ b/DEPLOYMENTS.md @@ -265,8 +265,10 @@ | `Gateway` | `etherspot` | 0x432defD2b3733e6fEBb1bD4B17Ed85D15b882163 | 0xba898531d95380c97307201fb1fe773801fb83343d9096c6bc4380402ed4486b | | `GatewayV2` | `goerli` | [0xBEd52610518788B931f7825301909e7616273d47](https://goerli.etherscan.io/address/0xBEd52610518788B931f7825301909e7616273d47) | [0x5d1526546b15cc9c23dfdda9c05c66db27468bcdf75f3dbc3ce43d63670e96d8](https://goerli.etherscan.io/tx/0x5d1526546b15cc9c23dfdda9c05c66db27468bcdf75f3dbc3ce43d63670e96d8) | | `GatewayV2` | `sokol` | [0xBEd52610518788B931f7825301909e7616273d47](https://blockscout.com/poa/sokol/address/0xBEd52610518788B931f7825301909e7616273d47) | [0xc39568a814d9b8e6137049bc34403b6940bdec03545f304778558ff1444ee393](https://blockscout.com/poa/sokol/tx/0xc39568a814d9b8e6137049bc34403b6940bdec03545f304778558ff1444ee393) | +| `GatewayV2` | `bsc` | [0xBEd52610518788B931f7825301909e7616273d47](https://bscscan.com/address/0xBEd52610518788B931f7825301909e7616273d47) | [0x1bbb891a54b3c149a6c9c984ac9b056b734ff5dd003f90949dce471680675db5](https://bscscan.com/tx/0x1bbb891a54b3c149a6c9c984ac9b056b734ff5dd003f90949dce471680675db5) | | `GatewayV2` | `bscTest` | [0xBEd52610518788B931f7825301909e7616273d47](https://testnet.bscscan.com/address/0xBEd52610518788B931f7825301909e7616273d47) | [0xd56fecb8c5a6ce335048541beffab457e5e7681958270321da8fe51c34e934bf](https://testnet.bscscan.com/tx/0xd56fecb8c5a6ce335048541beffab457e5e7681958270321da8fe51c34e934bf) | | `GatewayV2` | `fantomTest` | [0xBEd52610518788B931f7825301909e7616273d47](https://explorer.testnet.fantom.network/address/0xBEd52610518788B931f7825301909e7616273d47) | [0xcce8ae16dd3a0eff4e5748005473002ebb2e0a758c02524290e52d85cf91652a](https://explorer.testnet.fantom.network/transactions/0xcce8ae16dd3a0eff4e5748005473002ebb2e0a758c02524290e52d85cf91652a) | +| `GatewayV2` | `matic` | [0xBEd52610518788B931f7825301909e7616273d47](https://polygonscan.com/address/0xBEd52610518788B931f7825301909e7616273d47) | [0x3a66776afcfe3f3f337d501653f713f5b7ed7920a52e7d9fa5fd9e11d2c1e511](https://polygonscan.com/tx/0x3a66776afcfe3f3f337d501653f713f5b7ed7920a52e7d9fa5fd9e11d2c1e511) | | `GatewayV2` | `fuji` | [0x9FC4DdE698E5cf1Ee8d6e2D25c835836d9af1C8F](https://testnet.snowtrace.io/address/0x9FC4DdE698E5cf1Ee8d6e2D25c835836d9af1C8F) | [0x8db8b0e7e1e833d4b9ef812bf06fb7338ac25b496447512b5677436a4640a8d0](https://testnet.snowtrace.io/tx/0x8db8b0e7e1e833d4b9ef812bf06fb7338ac25b496447512b5677436a4640a8d0) | | `GatewayV2` | `arbitrumTest` | 0xBEd52610518788B931f7825301909e7616273d47 | 0x12a452e4cf52ed74b5c7baab0581cc622661636c1f0b12be016b85765395af4a | | `HopFacet` | `goerli` | [0x9B950aa30575F3d1E33bd0b2DD0AF4DE496F39F5](https://goerli.etherscan.io/address/0x9B950aa30575F3d1E33bd0b2DD0AF4DE496F39F5) | [0xfda9425406016686c3ce58061d202827338ee9de02e0974e5e1af7ec845824b2](https://goerli.etherscan.io/tx/0xfda9425406016686c3ce58061d202827338ee9de02e0974e5e1af7ec845824b2) | diff --git a/artifacts/console.json b/artifacts/console.json deleted file mode 100644 index 3e33d764..00000000 --- a/artifacts/console.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "console", - "sourceName": "hardhat/console.sol", - "abi": [], - "bytecode": "0x602d6050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c634300080f000a", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c634300080f000a", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/deployments/bsc/GatewayV2.json b/deployments/bsc/GatewayV2.json new file mode 100644 index 00000000..413f70ee --- /dev/null +++ b/deployments/bsc/GatewayV2.json @@ -0,0 +1,926 @@ +{ + "address": "0xBEd52610518788B931f7825301909e7616273d47", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "batch", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bool", + "name": "succeeded", + "type": "bool" + } + ], + "name": "BatchDelegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "GuardianAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "GuardianRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "initializer", + "type": "address" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "addGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "chainId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatchGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatchWithGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatchWithGasPriceGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "batches", + "type": "bytes[]" + }, + { + "internalType": "bool", + "name": "revertOnFailure", + "type": "bool" + } + ], + "name": "delegateBatches", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "batches", + "type": "bytes[]" + }, + { + "internalType": "bool", + "name": "revertOnFailure", + "type": "bool" + } + ], + "name": "delegateBatchesGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "externalAccountRegistry", + "outputs": [ + { + "internalType": "contract ExternalAccountRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountNextNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "internalType": "struct GatewayV2.DelegatedBatch", + "name": "delegatedBatch", + "type": "tuple" + } + ], + "name": "hashDelegatedBatch", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "uint256", + "name": "gasPrice", + "type": "uint256" + } + ], + "internalType": "struct GatewayV2.DelegatedBatchWithGasPrice", + "name": "delegatedBatch", + "type": "tuple" + } + ], + "name": "hashDelegatedBatchWithGasPrice", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ExternalAccountRegistry", + "name": "externalAccountRegistry_", + "type": "address" + }, + { + "internalType": "contract PersonalAccountRegistry", + "name": "personalAccountRegistry_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "isGuardian", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "personalAccountRegistry", + "outputs": [ + { + "internalType": "contract PersonalAccountRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "removeGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatchFromAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatchFromAccountGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatchGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "messageHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "verifyGuardianSignature", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x1bbb891a54b3c149a6c9c984ac9b056b734ff5dd003f90949dce471680675db5", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0x09FD4F6088f2025427AB1e89257A44747081Ed59", + "contractAddress": null, + "transactionIndex": 1, + "gasUsed": "2818644", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xa844c986a1fd162d5c183a0d4390f74ef3cecc222f8bd009f4625ab7ba1ffa36", + "transactionHash": "0x1bbb891a54b3c149a6c9c984ac9b056b734ff5dd003f90949dce471680675db5", + "logs": [], + "blockNumber": 22256786, + "cumulativeGasUsed": "2869795", + "status": 1, + "byzantium": true + }, + "args": [], + "solcInputHash": "8f6f179d2c9d29fd59e34814c3f7994c", + "metadata": "{\"compiler\":{\"version\":\"0.6.12+commit.27d51765\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"batch\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"succeeded\",\"type\":\"bool\"}],\"name\":\"BatchDelegated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"GuardianAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"GuardianRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"initializer\",\"type\":\"address\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"addGuardian\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatchGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatchWithGasPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatchWithGasPriceGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"batches\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"revertOnFailure\",\"type\":\"bool\"}],\"name\":\"delegateBatches\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"batches\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"revertOnFailure\",\"type\":\"bool\"}],\"name\":\"delegateBatchesGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"externalAccountRegistry\",\"outputs\":[{\"internalType\":\"contract ExternalAccountRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAccountNextNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"internalType\":\"struct GatewayV2.DelegatedBatch\",\"name\":\"delegatedBatch\",\"type\":\"tuple\"}],\"name\":\"hashDelegatedBatch\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"}],\"internalType\":\"struct GatewayV2.DelegatedBatchWithGasPrice\",\"name\":\"delegatedBatch\",\"type\":\"tuple\"}],\"name\":\"hashDelegatedBatchWithGasPrice\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ExternalAccountRegistry\",\"name\":\"externalAccountRegistry_\",\"type\":\"address\"},{\"internalType\":\"contract PersonalAccountRegistry\",\"name\":\"personalAccountRegistry_\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"isGuardian\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isInitialized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"personalAccountRegistry\",\"outputs\":[{\"internalType\":\"contract PersonalAccountRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"removeGuardian\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatchFromAccount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatchFromAccountGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatchGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"verifyGuardianSignature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Utkir Sobirov \",\"events\":{\"BatchDelegated(address,bytes,bool)\":{\"details\":\"Emitted when the single batch is delegated\",\"params\":{\"batch\":\"batch\",\"sender\":\"sender address\",\"succeeded\":\"if succeeded\"}}},\"kind\":\"dev\",\"methods\":{\"addGuardian(address)\":{\"params\":{\"guardian\":\"guardian address\"}},\"constructor\":{\"details\":\"Public constructor\"},\"delegateBatch(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatchGuarded(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatches(bytes[],bool)\":{\"details\":\"It will revert when all batches fail\",\"params\":{\"batches\":\"array of batches\",\"revertOnFailure\":\"reverts on any error\"}},\"delegateBatchesGuarded(bytes[],bool)\":{\"details\":\"It will revert when all batches fail\",\"params\":{\"batches\":\"array of batches\",\"revertOnFailure\":\"reverts on any error\"}},\"getAccountNextNonce(address)\":{\"params\":{\"account\":\"account address\"},\"returns\":{\"_0\":\"next nonce\"}},\"hashDelegatedBatch((address,uint256,address[],bytes[]))\":{\"params\":{\"delegatedBatch\":\"struct\"},\"returns\":{\"_0\":\"hash\"}},\"hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))\":{\"params\":{\"delegatedBatch\":\"struct\"},\"returns\":{\"_0\":\"hash\"}},\"initialize(address,address)\":{\"params\":{\"externalAccountRegistry_\":\"`ExternalAccountRegistry` contract address\",\"personalAccountRegistry_\":\"`PersonalAccountRegistry` contract address\"}},\"isGuardian(address)\":{\"params\":{\"guardian\":\"guardian address\"},\"returns\":{\"_0\":\"true when guardian exists\"}},\"isInitialized()\":{\"returns\":{\"_0\":\"true when contract is initialized\"}},\"removeGuardian(address)\":{\"params\":{\"guardian\":\"guardian address\"}},\"sendBatch(address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`\",\"params\":{\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"sendBatchFromAccount(address,address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"sendBatchFromAccountGuarded(address,address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"sendBatchGuarded(address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`\",\"params\":{\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"verifyGuardianSignature(bytes32,bytes)\":{\"params\":{\"messageHash\":\"message hash\",\"signature\":\"signature\"},\"returns\":{\"_0\":\"true on correct guardian signature\"}}},\"title\":\"Gateway V2 with guarded batching functions\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addGuardian(address)\":{\"notice\":\"Adds a new guardian\"},\"delegateBatch(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates batch from the account\"},\"delegateBatchGuarded(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates guarded batch from the account\"},\"delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates batch from the account (with gas price)\"},\"delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates guarded batch from the account (with gas price)\"},\"delegateBatches(bytes[],bool)\":{\"notice\":\"Delegates multiple batches\"},\"delegateBatchesGuarded(bytes[],bool)\":{\"notice\":\"Delegates multiple guarded batches\"},\"getAccountNextNonce(address)\":{\"notice\":\"Gets next account nonce\"},\"hashDelegatedBatch((address,uint256,address[],bytes[]))\":{\"notice\":\"Hashes `DelegatedBatch` message payload\"},\"hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))\":{\"notice\":\"Hashes `DelegatedBatchWithGasPrice` message payload\"},\"initialize(address,address)\":{\"notice\":\"Initializes `Gateway` contract\"},\"isGuardian(address)\":{\"notice\":\"Check if guardian exists\"},\"isInitialized()\":{\"notice\":\"Check if contract is initialized\"},\"removeGuardian(address)\":{\"notice\":\"Removes the existing guardian\"},\"sendBatch(address[],bytes[])\":{\"notice\":\"Sends batch\"},\"sendBatchFromAccount(address,address[],bytes[])\":{\"notice\":\"Sends batch from the account\"},\"sendBatchFromAccountGuarded(address,address[],bytes[])\":{\"notice\":\"Sends guarded batch from the account\"},\"sendBatchGuarded(address[],bytes[])\":{\"notice\":\"Sends guarded batch\"},\"verifyGuardianSignature(bytes32,bytes)\":{\"notice\":\"Verifies guardian signature\"}},\"notice\":\"GSN replacement\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/gateway/GatewayV2.sol\":\"GatewayV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/common/access/Controlled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.6.12;\\n\\n/**\\n * @title Controlled\\n *\\n * @dev Contract module which provides an access control mechanism.\\n * It ensures there is only one controlling account of the smart contract\\n * and grants that account exclusive access to specific functions.\\n *\\n * The controller account will be the one that deploys the contract.\\n *\\n * @author Stanis\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xdf03a0b7ec644da9925c5c1b6c8a86bb1cc1b9c5018bb265a1a4c5044b877af3\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x4a5f5670041362e87ea267d81c55fc3edc1a78e81f6f17524b13267f91f31458\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xe516c999a02a65ee99487d398d0c12589500680a9ca08c852540fb9473d70a26\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\n */\\ncontract AccountBase {\\n address public registry;\\n}\\n\",\"keccak256\":\"0xcadf29e389f8db823e14f3f92808fd135f07b0135eb4dcf29b89c85941b39862\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xe161f1f4f6ea5d3a9810f7c93764d55e473abe1054e6aa68fde791be7d70a26c\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x2d40245721f5f74219e5cf88713246dbe8b6d5404e941125d3e850b1f127ec34\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x9205536bc211f86d1113118a44dddfa7a9b9772a918cf4b1575c982a05472587\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x64c84964ea91bfb1f2d859eea6c57fe5b4a6f269951a4adf5f58d306c54c7f76\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x83e6056caaba892d91de45324f4d2702ac01695fab2d34c86895d7d288547ba3\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x3b1460d688302eb595268c2af147ab532f29dbced66520e013f48d498eed3cec\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x6089f354ca754d9c5dd9e800ee5ed86717dbf8f9af470604e0be691ac57c0107\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x4110150d0c921fd31db34ca33672de8e81c3ae467076149a3a546f804d1f58dd\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x3d47b2864dde5bde245917f7ac416a9e9715cdf1d226897e49838eb3186ee067\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xc1168f7ccb74aea67089941dc5e4c1d1c4aa766afca47a90c0b017b8445b8acf\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x6f2b0bd08da549c6c1f5ceee85766832d587dde62c56bebc3a14bd9ea407e03d\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x8067b1fae41b73949f8d871a835533cbdd94b9ca3faa93b91f595c37e632ccdb\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xe3fd29479d748d67360c61a9cbaafc66eaca25f476e59a45e842472bcf5233fc\",\"license\":\"MIT\"},\"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 \\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\",\"keccak256\":\"0x1721c8d16aaaf1ebde4eacf8f668a673ec80190769d85099d080840b4f4933a6\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xdae162610e707ab8c394b3edf924b75ef1f315520935cb88f4280b29eeaf4b61\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50326000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000469050806001819055505061315e8061006d6000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806387d31313116100b8578063b5021b161161007c578063b5021b1614610349578063d0f710d614610365578063d2c83b9a14610395578063d305d0db146103b3578063d9f13021146103cf578063f92c5f7c146103eb57610142565b806387d31313146102b95780639a8a0592146102d75780639f255626146102f5578063a526d83b14610311578063ac2a08cd1461032d57610142565b8063538901341161010a57806353890134146101e95780635afaa7bb14610205578063714041561461022157806373e5a13f1461023d57806376db2b4c1461026d578063867519c61461029d57610142565b80630c68ba2114610147578063231badaf14610177578063371aa71a14610193578063392e53cd146101af578063485cc955146101cd575b600080fd5b610161600480360381019061015c9190611e5b565b61041b565b60405161016e9190612b23565b60405180910390f35b610191600480360381019061018c9190611f03565b610471565b005b6101ad60048036038101906101a89190611f03565b61056c565b005b6101b761060c565b6040516101c49190612b23565b60405180910390f35b6101e760048036038101906101e29190612103565b610662565b005b61020360048036038101906101fe9190611fc2565b6107fa565b005b61021f600480360381019061021a919061202e565b610894565b005b61023b60048036038101906102369190611e5b565b610a6c565b005b61025760048036038101906102529190612180565b610c87565b6040516102649190612b3e565b60405180910390f35b6102876004803603810190610282919061213f565b610cac565b6040516102949190612b3e565b60405180910390f35b6102b760048036038101906102b29190611e84565b610cd6565b005b6102c1610ce7565b6040516102ce9190612bb9565b60405180910390f35b6102df610d0d565b6040516102ec9190612df4565b60405180910390f35b61030f600480360381019061030a9190611fc2565b610d13565b005b61032b60048036038101906103269190611e5b565b610d23565b005b61034760048036038101906103429190611f03565b610dbb565b005b610363600480360381019061035e9190611f03565b610e5b565b005b61037f600480360381019061037a91906120ab565b610f57565b60405161038c9190612b23565b60405180910390f35b61039d610fb0565b6040516103aa9190612b9e565b60405180910390f35b6103cd60048036038101906103c89190611e84565b610fd6565b005b6103e960048036038101906103e4919061202e565b611072565b005b61040560048036038101906104009190611e5b565b61110c565b6040516104129190612df4565b60405180910390f35b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484116104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e990612c54565b60405180910390fd5b60006105128261050488888888611168565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061056486828686611286565b505050505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166105f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ef90612cf4565b60405180910390fd5b6106058585858585610e5b565b5050505050565b60008073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e790612c14565b60405180910390fd5b60008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060606107be816116f1565b507f908408e307fc569b417f6cbec5d5a06f44a0a505ac0479b47d421a4b2fd6a1e6326040516107ee9190612a78565b60405180910390a15050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161087d90612cf4565b60405180910390fd5b6108908282610d13565b5050565b60008251116108d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108cf90612c94565b60405180910390fd5b600080600090505b8351811015610a265760003073ffffffffffffffffffffffffffffffffffffffff1685838151811061090e57fe5b60200260200101516040516109239190612994565b6000604051808303816000865af19150503d8060008114610960576040519150601f19603f3d011682016040523d82523d6000602084013e610965565b606091505b5050905083156109b457806109af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a690612c34565b60405180910390fd5b6109ca565b8080156109bf575082155b156109c957600192505b5b7f361c14722cc344132c73396113f7164232448b09c544a149f09048648b43d872338684815181106109f857fe5b602002602001015183604051610a1093929190612abc565b60405180910390a15080806001019150506108e0565b5080610a67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5e90612dd4565b60405180910390fd5b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610af8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aef90612cf4565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff161415610b67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5e90612db4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610bf3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bea90612d14565b60405180910390fd5b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fee943cdb81826d5909c559c6b1ae6908fcaf2dbc16c4b730346736b486283e8b3282604051610c7c929190612a93565b60405180910390a150565b6000610ca58260000151836020015184604001518560600151611168565b9050919050565b6000610ccf82600001518360200151846040015185606001518660800151611749565b9050919050565b610ce283338484611286565b505050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b610d1f33338484611286565b5050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610daf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610da690612cf4565b60405180910390fd5b610db8816117af565b50565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610e47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3e90612cf4565b60405180910390fd5b610e548585858585610471565b5050505050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548411610edc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ed390612c54565b60405180910390fd5b6000610efd82610eef888888883a611749565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610f4f86828686611286565b505050505050565b6000610fa78484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611940565b90509392505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611062576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105990612cf4565b60405180910390fd5b61106d838383610cd6565b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166110fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110f590612cf4565b60405180910390fd5b6111088282610894565b5050565b60006111616001600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546119ae90919063ffffffff16565b9050919050565b60006111c17f6848d0622081db2451400280dead7a739a080cb93852607c381af11e289769b286868661119a87611a03565b6040516020016111ad94939291906128f7565b604051602081830303815290604052611a66565b9050949350505050565b6000806000905060418351141561127c5760008060006020860151925060408601519150606086015160001a9050601b8160ff16101561120c57601b810190505b601b8160ff1614806112215750601c8160ff16145b1561127857600187828585604051600081526020016040526040516112499493929190612b59565b6020604051602081039080840390855afa15801561126b573d6000803e3d6000fd5b5050506020604051035193505b5050505b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156112f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ed90612c74565b60405180910390fd5b600082511161133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161133190612d94565b60405180910390fd5b815181511461137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137590612cd4565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461155257600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b815260040161140e929190612afa565b60206040518083038186803b15801561142657600080fd5b505afa15801561143a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145e9190612082565b806115125750600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b81526004016114c1929190612afa565b60206040518083038186803b1580156114d957600080fd5b505afa1580156114ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115119190612082565b5b611551576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161154890612cb4565b60405180910390fd5b5b600080600090505b82518110156116e957600073ffffffffffffffffffffffffffffffffffffffff1684828151811061158757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614156115e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115dd90612bd4565b60405180910390fd5b8381815181106115f257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1683828151811061161c57fe5b60200260200101518787604051602001611638939291906129ab565b6040516020818303038152906040526040516116549190612994565b6000604051808303816000865af19150503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b505080925050816116dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d390612d34565b60405180910390fd5b808060010191505061155a565b505050505050565b60008151141561170957611704326117af565b611746565b60008151905060005b818110156117435761173683828151811061172957fe5b60200260200101516117af565b8080600101915050611712565b50505b50565b60006117a47f6f4e1b2b1e5e49f4269e19e16e67a00cb0a796d96d30be3e4b540d3732e8bcad87878761177b88611a03565b8760405160200161179095949392919061293d565b604051602081830303815290604052611a66565b905095945050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561181f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161181690612bf4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156118ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a390612d74565b60405180910390fd5b6001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a3282604051611935929190612a93565b60405180910390a150565b60008061195683856111cb90919063ffffffff16565b9050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1691505092915050565b6000808284019050838110156119f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f090612d54565b60405180910390fd5b8091505092915050565b60608060008351905060005b81811015611a5b5782858281518110611a2457fe5b6020026020010151604051602001611a3d9291906129e4565b60405160208183030381529060405292508080600101915050611a0f565b508192505050919050565b6000611a9f600154308585604051602001611a849493929190612a2e565b60405160208183030381529060405280519060200120611aa7565b905092915050565b600081604051602001611aba9190612a08565b604051602081830303815290604052805190602001209050919050565b600081359050611ae6816130c7565b92915050565b600082601f830112611afd57600080fd5b8135611b10611b0b82612e3c565b612e0f565b91508181835260208401935060208101905083856020840282011115611b3557600080fd5b60005b83811015611b655781611b4b8882611ad7565b845260208401935060208301925050600181019050611b38565b5050505092915050565b600082601f830112611b8057600080fd5b8135611b93611b8e82612e64565b612e0f565b9150818183526020840193506020810190508360005b83811015611bd95781358601611bbf8882611c6c565b845260208401935060208301925050600181019050611ba9565b5050505092915050565b600081359050611bf2816130de565b92915050565b600081519050611c07816130de565b92915050565b600081359050611c1c816130f5565b92915050565b60008083601f840112611c3457600080fd5b8235905067ffffffffffffffff811115611c4d57600080fd5b602083019150836001820283011115611c6557600080fd5b9250929050565b600082601f830112611c7d57600080fd5b8135611c90611c8b82612e8c565b612e0f565b91508082526020830160208301858383011115611cac57600080fd5b611cb783828461302f565b50505092915050565b600081359050611ccf8161310c565b92915050565b600081359050611ce481613123565b92915050565b600060a08284031215611cfc57600080fd5b611d0660a0612e0f565b90506000611d1684828501611ad7565b6000830152506020611d2a84828501611e46565b602083015250604082013567ffffffffffffffff811115611d4a57600080fd5b611d5684828501611aec565b604083015250606082013567ffffffffffffffff811115611d7657600080fd5b611d8284828501611b6f565b6060830152506080611d9684828501611e46565b60808301525092915050565b600060808284031215611db457600080fd5b611dbe6080612e0f565b90506000611dce84828501611ad7565b6000830152506020611de284828501611e46565b602083015250604082013567ffffffffffffffff811115611e0257600080fd5b611e0e84828501611aec565b604083015250606082013567ffffffffffffffff811115611e2e57600080fd5b611e3a84828501611b6f565b60608301525092915050565b600081359050611e558161313a565b92915050565b600060208284031215611e6d57600080fd5b6000611e7b84828501611ad7565b91505092915050565b600080600060608486031215611e9957600080fd5b6000611ea786828701611ad7565b935050602084013567ffffffffffffffff811115611ec457600080fd5b611ed086828701611aec565b925050604084013567ffffffffffffffff811115611eed57600080fd5b611ef986828701611b6f565b9150509250925092565b600080600080600060a08688031215611f1b57600080fd5b6000611f2988828901611ad7565b9550506020611f3a88828901611e46565b945050604086013567ffffffffffffffff811115611f5757600080fd5b611f6388828901611aec565b935050606086013567ffffffffffffffff811115611f8057600080fd5b611f8c88828901611b6f565b925050608086013567ffffffffffffffff811115611fa957600080fd5b611fb588828901611c6c565b9150509295509295909350565b60008060408385031215611fd557600080fd5b600083013567ffffffffffffffff811115611fef57600080fd5b611ffb85828601611aec565b925050602083013567ffffffffffffffff81111561201857600080fd5b61202485828601611b6f565b9150509250929050565b6000806040838503121561204157600080fd5b600083013567ffffffffffffffff81111561205b57600080fd5b61206785828601611b6f565b925050602061207885828601611be3565b9150509250929050565b60006020828403121561209457600080fd5b60006120a284828501611bf8565b91505092915050565b6000806000604084860312156120c057600080fd5b60006120ce86828701611c0d565b935050602084013567ffffffffffffffff8111156120eb57600080fd5b6120f786828701611c22565b92509250509250925092565b6000806040838503121561211657600080fd5b600061212485828601611cc0565b925050602061213585828601611cd5565b9150509250929050565b60006020828403121561215157600080fd5b600082013567ffffffffffffffff81111561216b57600080fd5b61217784828501611cea565b91505092915050565b60006020828403121561219257600080fd5b600082013567ffffffffffffffff8111156121ac57600080fd5b6121b884828501611da2565b91505092915050565b60006121cd83836121f7565b60208301905092915050565b6121e281612fb1565b82525050565b6121f181612f2e565b82525050565b61220081612f2e565b82525050565b61221761221282612f2e565b613071565b82525050565b600061222882612ec8565b6122328185612eeb565b935061223d83612eb8565b8060005b8381101561226e57815161225588826121c1565b975061226083612ede565b925050600181019050612241565b5085935050505092915050565b61228481612f40565b82525050565b61229381612f4c565b82525050565b6122aa6122a582612f4c565b613083565b82525050565b60006122bb82612ed3565b6122c58185612ef6565b93506122d581856020860161303e565b6122de816130a9565b840191505092915050565b60006122f482612ed3565b6122fe8185612f07565b935061230e81856020860161303e565b80840191505092915050565b61232381612fc3565b82525050565b61233281612fe7565b82525050565b6000612345601b83612f12565b91507f476174657761793a2063616e6e6f742073656e6420746f2030783000000000006000830152602082019050919050565b6000612385601c83612f23565b91507f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000830152601c82019050919050565b60006123c5602083612f12565b91507f477561726465643a2063616e6e6f74206164642030783020677561726469616e6000830152602082019050919050565b6000612405602f83612f12565b91507f496e697469616c697a61626c653a2074782e6f726967696e206973206e6f742060008301527f74686520696e697469616c697a657200000000000000000000000000000000006020830152604082019050919050565b600061246b601783612f12565b91507f476174657761793a2062617463682072657665727465640000000000000000006000830152602082019050919050565b60006124ab603283612f12565b91507f476174657761793a206e6f6e6365206973206c6f776572207468616e2063757260008301527f72656e74206163636f756e74206e6f6e636500000000000000000000000000006020830152604082019050919050565b6000612511602583612f12565b91507f476174657761793a2063616e6e6f742073656e642066726f6d2030783020616360008301527f636f756e740000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612577602683612f12565b91507f476174657761793a2063616e6e6f742064656c656761746520656d707479206260008301527f61746368657300000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006125dd602883612f12565b91507f476174657761793a2073656e646572206973206e6f7420746865206163636f7560008301527f6e74206f776e65720000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612643601683612f12565b91507f476174657761793a20696e76616c6964206261746368000000000000000000006000830152602082019050919050565b6000612683602683612f12565b91507f477561726465643a2074782e6f726967696e206973206e6f742074686520677560008301527f61726469616e00000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006126e9601f83612f12565b91507f477561726465643a20677561726469616e20646f65736e2774206578697374006000830152602082019050919050565b6000612729602383612f12565b91507f476174657761793a206261746368207472616e73616374696f6e20726576657260008301527f74656400000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b600061278f601e83612f12565b91507f536166654d6174684c69623a206164646974696f6e206f766572666c6f7700006000830152602082019050919050565b60006127cf602083612f12565b91507f477561726465643a20677561726469616e20616c7265616479206578697374736000830152602082019050919050565b600061280f602083612f12565b91507f476174657761793a2063616e6e6f742073656e6420656d7074792062617463686000830152602082019050919050565b600061284f601b83612f12565b91507f477561726465643a2063616e6e6f742072656d6f76652073656c6600000000006000830152602082019050919050565b600061288f601d83612f12565b91507f476174657761793a20616c6c20626174636865732072657665727465640000006000830152602082019050919050565b6128cb81612f9a565b82525050565b6128e26128dd82612f9a565b61309f565b82525050565b6128f181612fa4565b82525050565b60006129038287612206565b60148201915061291382866128d1565b602082019150612923828561221d565b915061292f82846122e9565b915081905095945050505050565b60006129498288612206565b60148201915061295982876128d1565b602082019150612969828661221d565b915061297582856122e9565b915061298182846128d1565b6020820191508190509695505050505050565b60006129a082846122e9565b915081905092915050565b60006129b782866122e9565b91506129c38285612206565b6014820191506129d38284612206565b601482019150819050949350505050565b60006129f082856122e9565b91506129fc82846122e9565b91508190509392505050565b6000612a1382612378565b9150612a1f8284612299565b60208201915081905092915050565b6000612a3a82876128d1565b602082019150612a4a8286612206565b601482019150612a5a8285612299565b602082019150612a6a82846122e9565b915081905095945050505050565b6000602082019050612a8d60008301846121d9565b92915050565b6000604082019050612aa860008301856121d9565b612ab560208301846121e8565b9392505050565b6000606082019050612ad160008301866121d9565b8181036020830152612ae381856122b0565b9050612af2604083018461227b565b949350505050565b6000604082019050612b0f60008301856121e8565b612b1c60208301846121e8565b9392505050565b6000602082019050612b38600083018461227b565b92915050565b6000602082019050612b53600083018461228a565b92915050565b6000608082019050612b6e600083018761228a565b612b7b60208301866128e8565b612b88604083018561228a565b612b95606083018461228a565b95945050505050565b6000602082019050612bb3600083018461231a565b92915050565b6000602082019050612bce6000830184612329565b92915050565b60006020820190508181036000830152612bed81612338565b9050919050565b60006020820190508181036000830152612c0d816123b8565b9050919050565b60006020820190508181036000830152612c2d816123f8565b9050919050565b60006020820190508181036000830152612c4d8161245e565b9050919050565b60006020820190508181036000830152612c6d8161249e565b9050919050565b60006020820190508181036000830152612c8d81612504565b9050919050565b60006020820190508181036000830152612cad8161256a565b9050919050565b60006020820190508181036000830152612ccd816125d0565b9050919050565b60006020820190508181036000830152612ced81612636565b9050919050565b60006020820190508181036000830152612d0d81612676565b9050919050565b60006020820190508181036000830152612d2d816126dc565b9050919050565b60006020820190508181036000830152612d4d8161271c565b9050919050565b60006020820190508181036000830152612d6d81612782565b9050919050565b60006020820190508181036000830152612d8d816127c2565b9050919050565b60006020820190508181036000830152612dad81612802565b9050919050565b60006020820190508181036000830152612dcd81612842565b9050919050565b60006020820190508181036000830152612ded81612882565b9050919050565b6000602082019050612e0960008301846128c2565b92915050565b6000604051905081810181811067ffffffffffffffff82111715612e3257600080fd5b8060405250919050565b600067ffffffffffffffff821115612e5357600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612e7b57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612ea357600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000612f3982612f7a565b9050919050565b60008115159050919050565b6000819050919050565b6000612f6182612f2e565b9050919050565b6000612f7382612f2e565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000612fbc8261300b565b9050919050565b6000612fce82612fd5565b9050919050565b6000612fe082612f7a565b9050919050565b6000612ff282612ff9565b9050919050565b600061300482612f7a565b9050919050565b60006130168261301d565b9050919050565b600061302882612f7a565b9050919050565b82818337600083830152505050565b60005b8381101561305c578082015181840152602081019050613041565b8381111561306b576000848401525b50505050565b600061307c8261308d565b9050919050565b6000819050919050565b6000613098826130ba565b9050919050565b6000819050919050565b6000601f19601f8301169050919050565b60008160601b9050919050565b6130d081612f2e565b81146130db57600080fd5b50565b6130e781612f40565b81146130f257600080fd5b50565b6130fe81612f4c565b811461310957600080fd5b50565b61311581612f56565b811461312057600080fd5b50565b61312c81612f68565b811461313757600080fd5b50565b61314381612f9a565b811461314e57600080fd5b5056fea164736f6c634300060c000a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101425760003560e01c806387d31313116100b8578063b5021b161161007c578063b5021b1614610349578063d0f710d614610365578063d2c83b9a14610395578063d305d0db146103b3578063d9f13021146103cf578063f92c5f7c146103eb57610142565b806387d31313146102b95780639a8a0592146102d75780639f255626146102f5578063a526d83b14610311578063ac2a08cd1461032d57610142565b8063538901341161010a57806353890134146101e95780635afaa7bb14610205578063714041561461022157806373e5a13f1461023d57806376db2b4c1461026d578063867519c61461029d57610142565b80630c68ba2114610147578063231badaf14610177578063371aa71a14610193578063392e53cd146101af578063485cc955146101cd575b600080fd5b610161600480360381019061015c9190611e5b565b61041b565b60405161016e9190612b23565b60405180910390f35b610191600480360381019061018c9190611f03565b610471565b005b6101ad60048036038101906101a89190611f03565b61056c565b005b6101b761060c565b6040516101c49190612b23565b60405180910390f35b6101e760048036038101906101e29190612103565b610662565b005b61020360048036038101906101fe9190611fc2565b6107fa565b005b61021f600480360381019061021a919061202e565b610894565b005b61023b60048036038101906102369190611e5b565b610a6c565b005b61025760048036038101906102529190612180565b610c87565b6040516102649190612b3e565b60405180910390f35b6102876004803603810190610282919061213f565b610cac565b6040516102949190612b3e565b60405180910390f35b6102b760048036038101906102b29190611e84565b610cd6565b005b6102c1610ce7565b6040516102ce9190612bb9565b60405180910390f35b6102df610d0d565b6040516102ec9190612df4565b60405180910390f35b61030f600480360381019061030a9190611fc2565b610d13565b005b61032b60048036038101906103269190611e5b565b610d23565b005b61034760048036038101906103429190611f03565b610dbb565b005b610363600480360381019061035e9190611f03565b610e5b565b005b61037f600480360381019061037a91906120ab565b610f57565b60405161038c9190612b23565b60405180910390f35b61039d610fb0565b6040516103aa9190612b9e565b60405180910390f35b6103cd60048036038101906103c89190611e84565b610fd6565b005b6103e960048036038101906103e4919061202e565b611072565b005b61040560048036038101906104009190611e5b565b61110c565b6040516104129190612df4565b60405180910390f35b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484116104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e990612c54565b60405180910390fd5b60006105128261050488888888611168565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061056486828686611286565b505050505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166105f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ef90612cf4565b60405180910390fd5b6106058585858585610e5b565b5050505050565b60008073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e790612c14565b60405180910390fd5b60008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060606107be816116f1565b507f908408e307fc569b417f6cbec5d5a06f44a0a505ac0479b47d421a4b2fd6a1e6326040516107ee9190612a78565b60405180910390a15050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161087d90612cf4565b60405180910390fd5b6108908282610d13565b5050565b60008251116108d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108cf90612c94565b60405180910390fd5b600080600090505b8351811015610a265760003073ffffffffffffffffffffffffffffffffffffffff1685838151811061090e57fe5b60200260200101516040516109239190612994565b6000604051808303816000865af19150503d8060008114610960576040519150601f19603f3d011682016040523d82523d6000602084013e610965565b606091505b5050905083156109b457806109af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a690612c34565b60405180910390fd5b6109ca565b8080156109bf575082155b156109c957600192505b5b7f361c14722cc344132c73396113f7164232448b09c544a149f09048648b43d872338684815181106109f857fe5b602002602001015183604051610a1093929190612abc565b60405180910390a15080806001019150506108e0565b5080610a67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5e90612dd4565b60405180910390fd5b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610af8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aef90612cf4565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff161415610b67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5e90612db4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610bf3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bea90612d14565b60405180910390fd5b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fee943cdb81826d5909c559c6b1ae6908fcaf2dbc16c4b730346736b486283e8b3282604051610c7c929190612a93565b60405180910390a150565b6000610ca58260000151836020015184604001518560600151611168565b9050919050565b6000610ccf82600001518360200151846040015185606001518660800151611749565b9050919050565b610ce283338484611286565b505050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b610d1f33338484611286565b5050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610daf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610da690612cf4565b60405180910390fd5b610db8816117af565b50565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610e47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3e90612cf4565b60405180910390fd5b610e548585858585610471565b5050505050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548411610edc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ed390612c54565b60405180910390fd5b6000610efd82610eef888888883a611749565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610f4f86828686611286565b505050505050565b6000610fa78484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611940565b90509392505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611062576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105990612cf4565b60405180910390fd5b61106d838383610cd6565b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166110fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110f590612cf4565b60405180910390fd5b6111088282610894565b5050565b60006111616001600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546119ae90919063ffffffff16565b9050919050565b60006111c17f6848d0622081db2451400280dead7a739a080cb93852607c381af11e289769b286868661119a87611a03565b6040516020016111ad94939291906128f7565b604051602081830303815290604052611a66565b9050949350505050565b6000806000905060418351141561127c5760008060006020860151925060408601519150606086015160001a9050601b8160ff16101561120c57601b810190505b601b8160ff1614806112215750601c8160ff16145b1561127857600187828585604051600081526020016040526040516112499493929190612b59565b6020604051602081039080840390855afa15801561126b573d6000803e3d6000fd5b5050506020604051035193505b5050505b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156112f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ed90612c74565b60405180910390fd5b600082511161133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161133190612d94565b60405180910390fd5b815181511461137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137590612cd4565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461155257600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b815260040161140e929190612afa565b60206040518083038186803b15801561142657600080fd5b505afa15801561143a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145e9190612082565b806115125750600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b81526004016114c1929190612afa565b60206040518083038186803b1580156114d957600080fd5b505afa1580156114ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115119190612082565b5b611551576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161154890612cb4565b60405180910390fd5b5b600080600090505b82518110156116e957600073ffffffffffffffffffffffffffffffffffffffff1684828151811061158757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614156115e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115dd90612bd4565b60405180910390fd5b8381815181106115f257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1683828151811061161c57fe5b60200260200101518787604051602001611638939291906129ab565b6040516020818303038152906040526040516116549190612994565b6000604051808303816000865af19150503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b505080925050816116dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d390612d34565b60405180910390fd5b808060010191505061155a565b505050505050565b60008151141561170957611704326117af565b611746565b60008151905060005b818110156117435761173683828151811061172957fe5b60200260200101516117af565b8080600101915050611712565b50505b50565b60006117a47f6f4e1b2b1e5e49f4269e19e16e67a00cb0a796d96d30be3e4b540d3732e8bcad87878761177b88611a03565b8760405160200161179095949392919061293d565b604051602081830303815290604052611a66565b905095945050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561181f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161181690612bf4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156118ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a390612d74565b60405180910390fd5b6001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a3282604051611935929190612a93565b60405180910390a150565b60008061195683856111cb90919063ffffffff16565b9050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1691505092915050565b6000808284019050838110156119f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f090612d54565b60405180910390fd5b8091505092915050565b60608060008351905060005b81811015611a5b5782858281518110611a2457fe5b6020026020010151604051602001611a3d9291906129e4565b60405160208183030381529060405292508080600101915050611a0f565b508192505050919050565b6000611a9f600154308585604051602001611a849493929190612a2e565b60405160208183030381529060405280519060200120611aa7565b905092915050565b600081604051602001611aba9190612a08565b604051602081830303815290604052805190602001209050919050565b600081359050611ae6816130c7565b92915050565b600082601f830112611afd57600080fd5b8135611b10611b0b82612e3c565b612e0f565b91508181835260208401935060208101905083856020840282011115611b3557600080fd5b60005b83811015611b655781611b4b8882611ad7565b845260208401935060208301925050600181019050611b38565b5050505092915050565b600082601f830112611b8057600080fd5b8135611b93611b8e82612e64565b612e0f565b9150818183526020840193506020810190508360005b83811015611bd95781358601611bbf8882611c6c565b845260208401935060208301925050600181019050611ba9565b5050505092915050565b600081359050611bf2816130de565b92915050565b600081519050611c07816130de565b92915050565b600081359050611c1c816130f5565b92915050565b60008083601f840112611c3457600080fd5b8235905067ffffffffffffffff811115611c4d57600080fd5b602083019150836001820283011115611c6557600080fd5b9250929050565b600082601f830112611c7d57600080fd5b8135611c90611c8b82612e8c565b612e0f565b91508082526020830160208301858383011115611cac57600080fd5b611cb783828461302f565b50505092915050565b600081359050611ccf8161310c565b92915050565b600081359050611ce481613123565b92915050565b600060a08284031215611cfc57600080fd5b611d0660a0612e0f565b90506000611d1684828501611ad7565b6000830152506020611d2a84828501611e46565b602083015250604082013567ffffffffffffffff811115611d4a57600080fd5b611d5684828501611aec565b604083015250606082013567ffffffffffffffff811115611d7657600080fd5b611d8284828501611b6f565b6060830152506080611d9684828501611e46565b60808301525092915050565b600060808284031215611db457600080fd5b611dbe6080612e0f565b90506000611dce84828501611ad7565b6000830152506020611de284828501611e46565b602083015250604082013567ffffffffffffffff811115611e0257600080fd5b611e0e84828501611aec565b604083015250606082013567ffffffffffffffff811115611e2e57600080fd5b611e3a84828501611b6f565b60608301525092915050565b600081359050611e558161313a565b92915050565b600060208284031215611e6d57600080fd5b6000611e7b84828501611ad7565b91505092915050565b600080600060608486031215611e9957600080fd5b6000611ea786828701611ad7565b935050602084013567ffffffffffffffff811115611ec457600080fd5b611ed086828701611aec565b925050604084013567ffffffffffffffff811115611eed57600080fd5b611ef986828701611b6f565b9150509250925092565b600080600080600060a08688031215611f1b57600080fd5b6000611f2988828901611ad7565b9550506020611f3a88828901611e46565b945050604086013567ffffffffffffffff811115611f5757600080fd5b611f6388828901611aec565b935050606086013567ffffffffffffffff811115611f8057600080fd5b611f8c88828901611b6f565b925050608086013567ffffffffffffffff811115611fa957600080fd5b611fb588828901611c6c565b9150509295509295909350565b60008060408385031215611fd557600080fd5b600083013567ffffffffffffffff811115611fef57600080fd5b611ffb85828601611aec565b925050602083013567ffffffffffffffff81111561201857600080fd5b61202485828601611b6f565b9150509250929050565b6000806040838503121561204157600080fd5b600083013567ffffffffffffffff81111561205b57600080fd5b61206785828601611b6f565b925050602061207885828601611be3565b9150509250929050565b60006020828403121561209457600080fd5b60006120a284828501611bf8565b91505092915050565b6000806000604084860312156120c057600080fd5b60006120ce86828701611c0d565b935050602084013567ffffffffffffffff8111156120eb57600080fd5b6120f786828701611c22565b92509250509250925092565b6000806040838503121561211657600080fd5b600061212485828601611cc0565b925050602061213585828601611cd5565b9150509250929050565b60006020828403121561215157600080fd5b600082013567ffffffffffffffff81111561216b57600080fd5b61217784828501611cea565b91505092915050565b60006020828403121561219257600080fd5b600082013567ffffffffffffffff8111156121ac57600080fd5b6121b884828501611da2565b91505092915050565b60006121cd83836121f7565b60208301905092915050565b6121e281612fb1565b82525050565b6121f181612f2e565b82525050565b61220081612f2e565b82525050565b61221761221282612f2e565b613071565b82525050565b600061222882612ec8565b6122328185612eeb565b935061223d83612eb8565b8060005b8381101561226e57815161225588826121c1565b975061226083612ede565b925050600181019050612241565b5085935050505092915050565b61228481612f40565b82525050565b61229381612f4c565b82525050565b6122aa6122a582612f4c565b613083565b82525050565b60006122bb82612ed3565b6122c58185612ef6565b93506122d581856020860161303e565b6122de816130a9565b840191505092915050565b60006122f482612ed3565b6122fe8185612f07565b935061230e81856020860161303e565b80840191505092915050565b61232381612fc3565b82525050565b61233281612fe7565b82525050565b6000612345601b83612f12565b91507f476174657761793a2063616e6e6f742073656e6420746f2030783000000000006000830152602082019050919050565b6000612385601c83612f23565b91507f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000830152601c82019050919050565b60006123c5602083612f12565b91507f477561726465643a2063616e6e6f74206164642030783020677561726469616e6000830152602082019050919050565b6000612405602f83612f12565b91507f496e697469616c697a61626c653a2074782e6f726967696e206973206e6f742060008301527f74686520696e697469616c697a657200000000000000000000000000000000006020830152604082019050919050565b600061246b601783612f12565b91507f476174657761793a2062617463682072657665727465640000000000000000006000830152602082019050919050565b60006124ab603283612f12565b91507f476174657761793a206e6f6e6365206973206c6f776572207468616e2063757260008301527f72656e74206163636f756e74206e6f6e636500000000000000000000000000006020830152604082019050919050565b6000612511602583612f12565b91507f476174657761793a2063616e6e6f742073656e642066726f6d2030783020616360008301527f636f756e740000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612577602683612f12565b91507f476174657761793a2063616e6e6f742064656c656761746520656d707479206260008301527f61746368657300000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006125dd602883612f12565b91507f476174657761793a2073656e646572206973206e6f7420746865206163636f7560008301527f6e74206f776e65720000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612643601683612f12565b91507f476174657761793a20696e76616c6964206261746368000000000000000000006000830152602082019050919050565b6000612683602683612f12565b91507f477561726465643a2074782e6f726967696e206973206e6f742074686520677560008301527f61726469616e00000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006126e9601f83612f12565b91507f477561726465643a20677561726469616e20646f65736e2774206578697374006000830152602082019050919050565b6000612729602383612f12565b91507f476174657761793a206261746368207472616e73616374696f6e20726576657260008301527f74656400000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b600061278f601e83612f12565b91507f536166654d6174684c69623a206164646974696f6e206f766572666c6f7700006000830152602082019050919050565b60006127cf602083612f12565b91507f477561726465643a20677561726469616e20616c7265616479206578697374736000830152602082019050919050565b600061280f602083612f12565b91507f476174657761793a2063616e6e6f742073656e6420656d7074792062617463686000830152602082019050919050565b600061284f601b83612f12565b91507f477561726465643a2063616e6e6f742072656d6f76652073656c6600000000006000830152602082019050919050565b600061288f601d83612f12565b91507f476174657761793a20616c6c20626174636865732072657665727465640000006000830152602082019050919050565b6128cb81612f9a565b82525050565b6128e26128dd82612f9a565b61309f565b82525050565b6128f181612fa4565b82525050565b60006129038287612206565b60148201915061291382866128d1565b602082019150612923828561221d565b915061292f82846122e9565b915081905095945050505050565b60006129498288612206565b60148201915061295982876128d1565b602082019150612969828661221d565b915061297582856122e9565b915061298182846128d1565b6020820191508190509695505050505050565b60006129a082846122e9565b915081905092915050565b60006129b782866122e9565b91506129c38285612206565b6014820191506129d38284612206565b601482019150819050949350505050565b60006129f082856122e9565b91506129fc82846122e9565b91508190509392505050565b6000612a1382612378565b9150612a1f8284612299565b60208201915081905092915050565b6000612a3a82876128d1565b602082019150612a4a8286612206565b601482019150612a5a8285612299565b602082019150612a6a82846122e9565b915081905095945050505050565b6000602082019050612a8d60008301846121d9565b92915050565b6000604082019050612aa860008301856121d9565b612ab560208301846121e8565b9392505050565b6000606082019050612ad160008301866121d9565b8181036020830152612ae381856122b0565b9050612af2604083018461227b565b949350505050565b6000604082019050612b0f60008301856121e8565b612b1c60208301846121e8565b9392505050565b6000602082019050612b38600083018461227b565b92915050565b6000602082019050612b53600083018461228a565b92915050565b6000608082019050612b6e600083018761228a565b612b7b60208301866128e8565b612b88604083018561228a565b612b95606083018461228a565b95945050505050565b6000602082019050612bb3600083018461231a565b92915050565b6000602082019050612bce6000830184612329565b92915050565b60006020820190508181036000830152612bed81612338565b9050919050565b60006020820190508181036000830152612c0d816123b8565b9050919050565b60006020820190508181036000830152612c2d816123f8565b9050919050565b60006020820190508181036000830152612c4d8161245e565b9050919050565b60006020820190508181036000830152612c6d8161249e565b9050919050565b60006020820190508181036000830152612c8d81612504565b9050919050565b60006020820190508181036000830152612cad8161256a565b9050919050565b60006020820190508181036000830152612ccd816125d0565b9050919050565b60006020820190508181036000830152612ced81612636565b9050919050565b60006020820190508181036000830152612d0d81612676565b9050919050565b60006020820190508181036000830152612d2d816126dc565b9050919050565b60006020820190508181036000830152612d4d8161271c565b9050919050565b60006020820190508181036000830152612d6d81612782565b9050919050565b60006020820190508181036000830152612d8d816127c2565b9050919050565b60006020820190508181036000830152612dad81612802565b9050919050565b60006020820190508181036000830152612dcd81612842565b9050919050565b60006020820190508181036000830152612ded81612882565b9050919050565b6000602082019050612e0960008301846128c2565b92915050565b6000604051905081810181811067ffffffffffffffff82111715612e3257600080fd5b8060405250919050565b600067ffffffffffffffff821115612e5357600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612e7b57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612ea357600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000612f3982612f7a565b9050919050565b60008115159050919050565b6000819050919050565b6000612f6182612f2e565b9050919050565b6000612f7382612f2e565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000612fbc8261300b565b9050919050565b6000612fce82612fd5565b9050919050565b6000612fe082612f7a565b9050919050565b6000612ff282612ff9565b9050919050565b600061300482612f7a565b9050919050565b60006130168261301d565b9050919050565b600061302882612f7a565b9050919050565b82818337600083830152505050565b60005b8381101561305c578082015181840152602081019050613041565b8381111561306b576000848401525b50505050565b600061307c8261308d565b9050919050565b6000819050919050565b6000613098826130ba565b9050919050565b6000819050919050565b6000601f19601f8301169050919050565b60008160601b9050919050565b6130d081612f2e565b81146130db57600080fd5b50565b6130e781612f40565b81146130f257600080fd5b50565b6130fe81612f4c565b811461310957600080fd5b50565b61311581612f56565b811461312057600080fd5b50565b61312c81612f68565b811461313757600080fd5b50565b61314381612f9a565b811461314e57600080fd5b5056fea164736f6c634300060c000a", + "devdoc": { + "author": "Utkir Sobirov ", + "events": { + "BatchDelegated(address,bytes,bool)": { + "details": "Emitted when the single batch is delegated", + "params": { + "batch": "batch", + "sender": "sender address", + "succeeded": "if succeeded" + } + } + }, + "kind": "dev", + "methods": { + "addGuardian(address)": { + "params": { + "guardian": "guardian address" + } + }, + "constructor": { + "details": "Public constructor" + }, + "delegateBatch(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatchGuarded(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatches(bytes[],bool)": { + "details": "It will revert when all batches fail", + "params": { + "batches": "array of batches", + "revertOnFailure": "reverts on any error" + } + }, + "delegateBatchesGuarded(bytes[],bool)": { + "details": "It will revert when all batches fail", + "params": { + "batches": "array of batches", + "revertOnFailure": "reverts on any error" + } + }, + "getAccountNextNonce(address)": { + "params": { + "account": "account address" + }, + "returns": { + "_0": "next nonce" + } + }, + "hashDelegatedBatch((address,uint256,address[],bytes[]))": { + "params": { + "delegatedBatch": "struct" + }, + "returns": { + "_0": "hash" + } + }, + "hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))": { + "params": { + "delegatedBatch": "struct" + }, + "returns": { + "_0": "hash" + } + }, + "initialize(address,address)": { + "params": { + "externalAccountRegistry_": "`ExternalAccountRegistry` contract address", + "personalAccountRegistry_": "`PersonalAccountRegistry` contract address" + } + }, + "isGuardian(address)": { + "params": { + "guardian": "guardian address" + }, + "returns": { + "_0": "true when guardian exists" + } + }, + "isInitialized()": { + "returns": { + "_0": "true when contract is initialized" + } + }, + "removeGuardian(address)": { + "params": { + "guardian": "guardian address" + } + }, + "sendBatch(address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`", + "params": { + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "sendBatchFromAccount(address,address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`", + "params": { + "account": "account address", + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "sendBatchFromAccountGuarded(address,address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`", + "params": { + "account": "account address", + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "sendBatchGuarded(address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`", + "params": { + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "verifyGuardianSignature(bytes32,bytes)": { + "params": { + "messageHash": "message hash", + "signature": "signature" + }, + "returns": { + "_0": "true on correct guardian signature" + } + } + }, + "title": "Gateway V2 with guarded batching functions", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "addGuardian(address)": { + "notice": "Adds a new guardian" + }, + "delegateBatch(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates batch from the account" + }, + "delegateBatchGuarded(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates guarded batch from the account" + }, + "delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates batch from the account (with gas price)" + }, + "delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates guarded batch from the account (with gas price)" + }, + "delegateBatches(bytes[],bool)": { + "notice": "Delegates multiple batches" + }, + "delegateBatchesGuarded(bytes[],bool)": { + "notice": "Delegates multiple guarded batches" + }, + "getAccountNextNonce(address)": { + "notice": "Gets next account nonce" + }, + "hashDelegatedBatch((address,uint256,address[],bytes[]))": { + "notice": "Hashes `DelegatedBatch` message payload" + }, + "hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))": { + "notice": "Hashes `DelegatedBatchWithGasPrice` message payload" + }, + "initialize(address,address)": { + "notice": "Initializes `Gateway` contract" + }, + "isGuardian(address)": { + "notice": "Check if guardian exists" + }, + "isInitialized()": { + "notice": "Check if contract is initialized" + }, + "removeGuardian(address)": { + "notice": "Removes the existing guardian" + }, + "sendBatch(address[],bytes[])": { + "notice": "Sends batch" + }, + "sendBatchFromAccount(address,address[],bytes[])": { + "notice": "Sends batch from the account" + }, + "sendBatchFromAccountGuarded(address,address[],bytes[])": { + "notice": "Sends guarded batch from the account" + }, + "sendBatchGuarded(address[],bytes[])": { + "notice": "Sends guarded batch" + }, + "verifyGuardianSignature(bytes32,bytes)": { + "notice": "Verifies guardian signature" + } + }, + "notice": "GSN replacement", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1227, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "initializer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 1291, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "chainId", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 40, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "guardians", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 2826, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "externalAccountRegistry", + "offset": 0, + "slot": "3", + "type": "t_contract(ExternalAccountRegistry)2009" + }, + { + "astId": 2828, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "personalAccountRegistry", + "offset": 0, + "slot": "4", + "type": "t_contract(PersonalAccountRegistry)4188" + }, + { + "astId": 2832, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "accountNonce", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_address,t_uint256)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(ExternalAccountRegistry)2009": { + "encoding": "inplace", + "label": "contract ExternalAccountRegistry", + "numberOfBytes": "20" + }, + "t_contract(PersonalAccountRegistry)4188": { + "encoding": "inplace", + "label": "contract PersonalAccountRegistry", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/bsc/solcInputs/8f6f179d2c9d29fd59e34814c3f7994c.json b/deployments/bsc/solcInputs/8f6f179d2c9d29fd59e34814c3f7994c.json new file mode 100644 index 00000000..29b6e22f --- /dev/null +++ b/deployments/bsc/solcInputs/8f6f179d2c9d29fd59e34814c3f7994c.json @@ -0,0 +1,94 @@ +{ + "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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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" + ] + } + } + } +} \ No newline at end of file diff --git a/deployments/matic/GatewayV2.json b/deployments/matic/GatewayV2.json new file mode 100644 index 00000000..e9abc265 --- /dev/null +++ b/deployments/matic/GatewayV2.json @@ -0,0 +1,942 @@ +{ + "address": "0xBEd52610518788B931f7825301909e7616273d47", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "batch", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bool", + "name": "succeeded", + "type": "bool" + } + ], + "name": "BatchDelegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "GuardianAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "GuardianRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "initializer", + "type": "address" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "addGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "chainId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatchGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatchWithGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "senderSignature", + "type": "bytes" + } + ], + "name": "delegateBatchWithGasPriceGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "batches", + "type": "bytes[]" + }, + { + "internalType": "bool", + "name": "revertOnFailure", + "type": "bool" + } + ], + "name": "delegateBatches", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "batches", + "type": "bytes[]" + }, + { + "internalType": "bool", + "name": "revertOnFailure", + "type": "bool" + } + ], + "name": "delegateBatchesGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "externalAccountRegistry", + "outputs": [ + { + "internalType": "contract ExternalAccountRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountNextNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "internalType": "struct GatewayV2.DelegatedBatch", + "name": "delegatedBatch", + "type": "tuple" + } + ], + "name": "hashDelegatedBatch", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + }, + { + "internalType": "uint256", + "name": "gasPrice", + "type": "uint256" + } + ], + "internalType": "struct GatewayV2.DelegatedBatchWithGasPrice", + "name": "delegatedBatch", + "type": "tuple" + } + ], + "name": "hashDelegatedBatchWithGasPrice", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ExternalAccountRegistry", + "name": "externalAccountRegistry_", + "type": "address" + }, + { + "internalType": "contract PersonalAccountRegistry", + "name": "personalAccountRegistry_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "isGuardian", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "personalAccountRegistry", + "outputs": [ + { + "internalType": "contract PersonalAccountRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "removeGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatchFromAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatchFromAccountGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "to", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "sendBatchGuarded", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "messageHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "verifyGuardianSignature", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x3a66776afcfe3f3f337d501653f713f5b7ed7920a52e7d9fa5fd9e11d2c1e511", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0x09FD4F6088f2025427AB1e89257A44747081Ed59", + "contractAddress": null, + "transactionIndex": 84, + "gasUsed": "2822044", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000004000000000004000000000000000000200000000000800000000000000000000000000000000000000200000000004000000000000000000001800000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000100002", + "blockHash": "0xaf53377a73e83b73afa8b47d43a645baf0f3f51ce802e1c06b2b6d96cbb17ba7", + "transactionHash": "0x3a66776afcfe3f3f337d501653f713f5b7ed7920a52e7d9fa5fd9e11d2c1e511", + "logs": [ + { + "transactionIndex": 84, + "blockNumber": 34460656, + "transactionHash": "0x3a66776afcfe3f3f337d501653f713f5b7ed7920a52e7d9fa5fd9e11d2c1e511", + "address": "0x0000000000000000000000000000000000001010", + "topics": [ + "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", + "0x0000000000000000000000000000000000000000000000000000000000001010", + "0x00000000000000000000000009fd4f6088f2025427ab1e89257a44747081ed59", + "0x00000000000000000000000046a3a41bd932244dd08186e4c19f1a7e48cbcdf4" + ], + "data": "0x0000000000000000000000000000000000000000000000000090c30b146c2a8c00000000000000000000000000000000000000000000000021cb63f2b2b362ba00000000000000000000000000000000000000000000291907b0e31e4afca5bc000000000000000000000000000000000000000000000000213aa0e79e47382e0000000000000000000000000000000000000000000029190841a6295f68d048", + "logIndex": 294, + "blockHash": "0xaf53377a73e83b73afa8b47d43a645baf0f3f51ce802e1c06b2b6d96cbb17ba7" + } + ], + "blockNumber": 34460656, + "cumulativeGasUsed": "17797942", + "status": 1, + "byzantium": true + }, + "args": [], + "solcInputHash": "8f6f179d2c9d29fd59e34814c3f7994c", + "metadata": "{\"compiler\":{\"version\":\"0.6.12+commit.27d51765\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"batch\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"succeeded\",\"type\":\"bool\"}],\"name\":\"BatchDelegated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"GuardianAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"GuardianRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"initializer\",\"type\":\"address\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"addGuardian\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatchGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatchWithGasPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"senderSignature\",\"type\":\"bytes\"}],\"name\":\"delegateBatchWithGasPriceGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"batches\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"revertOnFailure\",\"type\":\"bool\"}],\"name\":\"delegateBatches\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"batches\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"revertOnFailure\",\"type\":\"bool\"}],\"name\":\"delegateBatchesGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"externalAccountRegistry\",\"outputs\":[{\"internalType\":\"contract ExternalAccountRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAccountNextNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"internalType\":\"struct GatewayV2.DelegatedBatch\",\"name\":\"delegatedBatch\",\"type\":\"tuple\"}],\"name\":\"hashDelegatedBatch\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"}],\"internalType\":\"struct GatewayV2.DelegatedBatchWithGasPrice\",\"name\":\"delegatedBatch\",\"type\":\"tuple\"}],\"name\":\"hashDelegatedBatchWithGasPrice\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ExternalAccountRegistry\",\"name\":\"externalAccountRegistry_\",\"type\":\"address\"},{\"internalType\":\"contract PersonalAccountRegistry\",\"name\":\"personalAccountRegistry_\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"isGuardian\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isInitialized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"personalAccountRegistry\",\"outputs\":[{\"internalType\":\"contract PersonalAccountRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guardian\",\"type\":\"address\"}],\"name\":\"removeGuardian\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatchFromAccount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatchFromAccountGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"to\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"sendBatchGuarded\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"verifyGuardianSignature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Utkir Sobirov \",\"events\":{\"BatchDelegated(address,bytes,bool)\":{\"details\":\"Emitted when the single batch is delegated\",\"params\":{\"batch\":\"batch\",\"sender\":\"sender address\",\"succeeded\":\"if succeeded\"}}},\"kind\":\"dev\",\"methods\":{\"addGuardian(address)\":{\"params\":{\"guardian\":\"guardian address\"}},\"constructor\":{\"details\":\"Public constructor\"},\"delegateBatch(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatchGuarded(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)\":{\"details\":\"Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"nonce\":\"next account nonce\",\"senderSignature\":\"sender signature\",\"to\":\"array of batch recipients contracts\"}},\"delegateBatches(bytes[],bool)\":{\"details\":\"It will revert when all batches fail\",\"params\":{\"batches\":\"array of batches\",\"revertOnFailure\":\"reverts on any error\"}},\"delegateBatchesGuarded(bytes[],bool)\":{\"details\":\"It will revert when all batches fail\",\"params\":{\"batches\":\"array of batches\",\"revertOnFailure\":\"reverts on any error\"}},\"getAccountNextNonce(address)\":{\"params\":{\"account\":\"account address\"},\"returns\":{\"_0\":\"next nonce\"}},\"hashDelegatedBatch((address,uint256,address[],bytes[]))\":{\"params\":{\"delegatedBatch\":\"struct\"},\"returns\":{\"_0\":\"hash\"}},\"hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))\":{\"params\":{\"delegatedBatch\":\"struct\"},\"returns\":{\"_0\":\"hash\"}},\"initialize(address,address)\":{\"params\":{\"externalAccountRegistry_\":\"`ExternalAccountRegistry` contract address\",\"personalAccountRegistry_\":\"`PersonalAccountRegistry` contract address\"}},\"isGuardian(address)\":{\"params\":{\"guardian\":\"guardian address\"},\"returns\":{\"_0\":\"true when guardian exists\"}},\"isInitialized()\":{\"returns\":{\"_0\":\"true when contract is initialized\"}},\"removeGuardian(address)\":{\"params\":{\"guardian\":\"guardian address\"}},\"sendBatch(address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`\",\"params\":{\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"sendBatchFromAccount(address,address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"sendBatchFromAccountGuarded(address,address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`\",\"params\":{\"account\":\"account address\",\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"sendBatchGuarded(address[],bytes[])\":{\"details\":\"`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`\",\"params\":{\"data\":\"array of batch data\",\"to\":\"array of batch recipients contracts\"}},\"verifyGuardianSignature(bytes32,bytes)\":{\"params\":{\"messageHash\":\"message hash\",\"signature\":\"signature\"},\"returns\":{\"_0\":\"true on correct guardian signature\"}}},\"title\":\"Gateway V2 with guarded batching functions\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addGuardian(address)\":{\"notice\":\"Adds a new guardian\"},\"delegateBatch(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates batch from the account\"},\"delegateBatchGuarded(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates guarded batch from the account\"},\"delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates batch from the account (with gas price)\"},\"delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)\":{\"notice\":\"Delegates guarded batch from the account (with gas price)\"},\"delegateBatches(bytes[],bool)\":{\"notice\":\"Delegates multiple batches\"},\"delegateBatchesGuarded(bytes[],bool)\":{\"notice\":\"Delegates multiple guarded batches\"},\"getAccountNextNonce(address)\":{\"notice\":\"Gets next account nonce\"},\"hashDelegatedBatch((address,uint256,address[],bytes[]))\":{\"notice\":\"Hashes `DelegatedBatch` message payload\"},\"hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))\":{\"notice\":\"Hashes `DelegatedBatchWithGasPrice` message payload\"},\"initialize(address,address)\":{\"notice\":\"Initializes `Gateway` contract\"},\"isGuardian(address)\":{\"notice\":\"Check if guardian exists\"},\"isInitialized()\":{\"notice\":\"Check if contract is initialized\"},\"removeGuardian(address)\":{\"notice\":\"Removes the existing guardian\"},\"sendBatch(address[],bytes[])\":{\"notice\":\"Sends batch\"},\"sendBatchFromAccount(address,address[],bytes[])\":{\"notice\":\"Sends batch from the account\"},\"sendBatchFromAccountGuarded(address,address[],bytes[])\":{\"notice\":\"Sends guarded batch from the account\"},\"sendBatchGuarded(address[],bytes[])\":{\"notice\":\"Sends guarded batch\"},\"verifyGuardianSignature(bytes32,bytes)\":{\"notice\":\"Verifies guardian signature\"}},\"notice\":\"GSN replacement\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/gateway/GatewayV2.sol\":\"GatewayV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/common/access/Controlled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.6.12;\\n\\n/**\\n * @title Controlled\\n *\\n * @dev Contract module which provides an access control mechanism.\\n * It ensures there is only one controlling account of the smart contract\\n * and grants that account exclusive access to specific functions.\\n *\\n * The controller account will be the one that deploys the contract.\\n *\\n * @author Stanis\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xdf03a0b7ec644da9925c5c1b6c8a86bb1cc1b9c5018bb265a1a4c5044b877af3\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x4a5f5670041362e87ea267d81c55fc3edc1a78e81f6f17524b13267f91f31458\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xe516c999a02a65ee99487d398d0c12589500680a9ca08c852540fb9473d70a26\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\n */\\ncontract AccountBase {\\n address public registry;\\n}\\n\",\"keccak256\":\"0xcadf29e389f8db823e14f3f92808fd135f07b0135eb4dcf29b89c85941b39862\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xe161f1f4f6ea5d3a9810f7c93764d55e473abe1054e6aa68fde791be7d70a26c\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x2d40245721f5f74219e5cf88713246dbe8b6d5404e941125d3e850b1f127ec34\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x9205536bc211f86d1113118a44dddfa7a9b9772a918cf4b1575c982a05472587\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x64c84964ea91bfb1f2d859eea6c57fe5b4a6f269951a4adf5f58d306c54c7f76\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x83e6056caaba892d91de45324f4d2702ac01695fab2d34c86895d7d288547ba3\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x3b1460d688302eb595268c2af147ab532f29dbced66520e013f48d498eed3cec\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x6089f354ca754d9c5dd9e800ee5ed86717dbf8f9af470604e0be691ac57c0107\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x4110150d0c921fd31db34ca33672de8e81c3ae467076149a3a546f804d1f58dd\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x3d47b2864dde5bde245917f7ac416a9e9715cdf1d226897e49838eb3186ee067\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xc1168f7ccb74aea67089941dc5e4c1d1c4aa766afca47a90c0b017b8445b8acf\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x6f2b0bd08da549c6c1f5ceee85766832d587dde62c56bebc3a14bd9ea407e03d\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0x8067b1fae41b73949f8d871a835533cbdd94b9ca3faa93b91f595c37e632ccdb\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xe3fd29479d748d67360c61a9cbaafc66eaca25f476e59a45e842472bcf5233fc\",\"license\":\"MIT\"},\"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 \\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\",\"keccak256\":\"0x1721c8d16aaaf1ebde4eacf8f668a673ec80190769d85099d080840b4f4933a6\",\"license\":\"MIT\"},\"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\\u0142aw G\\u0142ogowski \\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\",\"keccak256\":\"0xdae162610e707ab8c394b3edf924b75ef1f315520935cb88f4280b29eeaf4b61\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50326000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000469050806001819055505061315e8061006d6000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806387d31313116100b8578063b5021b161161007c578063b5021b1614610349578063d0f710d614610365578063d2c83b9a14610395578063d305d0db146103b3578063d9f13021146103cf578063f92c5f7c146103eb57610142565b806387d31313146102b95780639a8a0592146102d75780639f255626146102f5578063a526d83b14610311578063ac2a08cd1461032d57610142565b8063538901341161010a57806353890134146101e95780635afaa7bb14610205578063714041561461022157806373e5a13f1461023d57806376db2b4c1461026d578063867519c61461029d57610142565b80630c68ba2114610147578063231badaf14610177578063371aa71a14610193578063392e53cd146101af578063485cc955146101cd575b600080fd5b610161600480360381019061015c9190611e5b565b61041b565b60405161016e9190612b23565b60405180910390f35b610191600480360381019061018c9190611f03565b610471565b005b6101ad60048036038101906101a89190611f03565b61056c565b005b6101b761060c565b6040516101c49190612b23565b60405180910390f35b6101e760048036038101906101e29190612103565b610662565b005b61020360048036038101906101fe9190611fc2565b6107fa565b005b61021f600480360381019061021a919061202e565b610894565b005b61023b60048036038101906102369190611e5b565b610a6c565b005b61025760048036038101906102529190612180565b610c87565b6040516102649190612b3e565b60405180910390f35b6102876004803603810190610282919061213f565b610cac565b6040516102949190612b3e565b60405180910390f35b6102b760048036038101906102b29190611e84565b610cd6565b005b6102c1610ce7565b6040516102ce9190612bb9565b60405180910390f35b6102df610d0d565b6040516102ec9190612df4565b60405180910390f35b61030f600480360381019061030a9190611fc2565b610d13565b005b61032b60048036038101906103269190611e5b565b610d23565b005b61034760048036038101906103429190611f03565b610dbb565b005b610363600480360381019061035e9190611f03565b610e5b565b005b61037f600480360381019061037a91906120ab565b610f57565b60405161038c9190612b23565b60405180910390f35b61039d610fb0565b6040516103aa9190612b9e565b60405180910390f35b6103cd60048036038101906103c89190611e84565b610fd6565b005b6103e960048036038101906103e4919061202e565b611072565b005b61040560048036038101906104009190611e5b565b61110c565b6040516104129190612df4565b60405180910390f35b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484116104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e990612c54565b60405180910390fd5b60006105128261050488888888611168565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061056486828686611286565b505050505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166105f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ef90612cf4565b60405180910390fd5b6106058585858585610e5b565b5050505050565b60008073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e790612c14565b60405180910390fd5b60008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060606107be816116f1565b507f908408e307fc569b417f6cbec5d5a06f44a0a505ac0479b47d421a4b2fd6a1e6326040516107ee9190612a78565b60405180910390a15050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161087d90612cf4565b60405180910390fd5b6108908282610d13565b5050565b60008251116108d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108cf90612c94565b60405180910390fd5b600080600090505b8351811015610a265760003073ffffffffffffffffffffffffffffffffffffffff1685838151811061090e57fe5b60200260200101516040516109239190612994565b6000604051808303816000865af19150503d8060008114610960576040519150601f19603f3d011682016040523d82523d6000602084013e610965565b606091505b5050905083156109b457806109af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a690612c34565b60405180910390fd5b6109ca565b8080156109bf575082155b156109c957600192505b5b7f361c14722cc344132c73396113f7164232448b09c544a149f09048648b43d872338684815181106109f857fe5b602002602001015183604051610a1093929190612abc565b60405180910390a15080806001019150506108e0565b5080610a67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5e90612dd4565b60405180910390fd5b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610af8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aef90612cf4565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff161415610b67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5e90612db4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610bf3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bea90612d14565b60405180910390fd5b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fee943cdb81826d5909c559c6b1ae6908fcaf2dbc16c4b730346736b486283e8b3282604051610c7c929190612a93565b60405180910390a150565b6000610ca58260000151836020015184604001518560600151611168565b9050919050565b6000610ccf82600001518360200151846040015185606001518660800151611749565b9050919050565b610ce283338484611286565b505050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b610d1f33338484611286565b5050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610daf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610da690612cf4565b60405180910390fd5b610db8816117af565b50565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610e47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3e90612cf4565b60405180910390fd5b610e548585858585610471565b5050505050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548411610edc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ed390612c54565b60405180910390fd5b6000610efd82610eef888888883a611749565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610f4f86828686611286565b505050505050565b6000610fa78484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611940565b90509392505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611062576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105990612cf4565b60405180910390fd5b61106d838383610cd6565b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166110fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110f590612cf4565b60405180910390fd5b6111088282610894565b5050565b60006111616001600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546119ae90919063ffffffff16565b9050919050565b60006111c17f6848d0622081db2451400280dead7a739a080cb93852607c381af11e289769b286868661119a87611a03565b6040516020016111ad94939291906128f7565b604051602081830303815290604052611a66565b9050949350505050565b6000806000905060418351141561127c5760008060006020860151925060408601519150606086015160001a9050601b8160ff16101561120c57601b810190505b601b8160ff1614806112215750601c8160ff16145b1561127857600187828585604051600081526020016040526040516112499493929190612b59565b6020604051602081039080840390855afa15801561126b573d6000803e3d6000fd5b5050506020604051035193505b5050505b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156112f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ed90612c74565b60405180910390fd5b600082511161133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161133190612d94565b60405180910390fd5b815181511461137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137590612cd4565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461155257600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b815260040161140e929190612afa565b60206040518083038186803b15801561142657600080fd5b505afa15801561143a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145e9190612082565b806115125750600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b81526004016114c1929190612afa565b60206040518083038186803b1580156114d957600080fd5b505afa1580156114ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115119190612082565b5b611551576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161154890612cb4565b60405180910390fd5b5b600080600090505b82518110156116e957600073ffffffffffffffffffffffffffffffffffffffff1684828151811061158757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614156115e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115dd90612bd4565b60405180910390fd5b8381815181106115f257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1683828151811061161c57fe5b60200260200101518787604051602001611638939291906129ab565b6040516020818303038152906040526040516116549190612994565b6000604051808303816000865af19150503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b505080925050816116dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d390612d34565b60405180910390fd5b808060010191505061155a565b505050505050565b60008151141561170957611704326117af565b611746565b60008151905060005b818110156117435761173683828151811061172957fe5b60200260200101516117af565b8080600101915050611712565b50505b50565b60006117a47f6f4e1b2b1e5e49f4269e19e16e67a00cb0a796d96d30be3e4b540d3732e8bcad87878761177b88611a03565b8760405160200161179095949392919061293d565b604051602081830303815290604052611a66565b905095945050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561181f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161181690612bf4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156118ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a390612d74565b60405180910390fd5b6001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a3282604051611935929190612a93565b60405180910390a150565b60008061195683856111cb90919063ffffffff16565b9050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1691505092915050565b6000808284019050838110156119f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f090612d54565b60405180910390fd5b8091505092915050565b60608060008351905060005b81811015611a5b5782858281518110611a2457fe5b6020026020010151604051602001611a3d9291906129e4565b60405160208183030381529060405292508080600101915050611a0f565b508192505050919050565b6000611a9f600154308585604051602001611a849493929190612a2e565b60405160208183030381529060405280519060200120611aa7565b905092915050565b600081604051602001611aba9190612a08565b604051602081830303815290604052805190602001209050919050565b600081359050611ae6816130c7565b92915050565b600082601f830112611afd57600080fd5b8135611b10611b0b82612e3c565b612e0f565b91508181835260208401935060208101905083856020840282011115611b3557600080fd5b60005b83811015611b655781611b4b8882611ad7565b845260208401935060208301925050600181019050611b38565b5050505092915050565b600082601f830112611b8057600080fd5b8135611b93611b8e82612e64565b612e0f565b9150818183526020840193506020810190508360005b83811015611bd95781358601611bbf8882611c6c565b845260208401935060208301925050600181019050611ba9565b5050505092915050565b600081359050611bf2816130de565b92915050565b600081519050611c07816130de565b92915050565b600081359050611c1c816130f5565b92915050565b60008083601f840112611c3457600080fd5b8235905067ffffffffffffffff811115611c4d57600080fd5b602083019150836001820283011115611c6557600080fd5b9250929050565b600082601f830112611c7d57600080fd5b8135611c90611c8b82612e8c565b612e0f565b91508082526020830160208301858383011115611cac57600080fd5b611cb783828461302f565b50505092915050565b600081359050611ccf8161310c565b92915050565b600081359050611ce481613123565b92915050565b600060a08284031215611cfc57600080fd5b611d0660a0612e0f565b90506000611d1684828501611ad7565b6000830152506020611d2a84828501611e46565b602083015250604082013567ffffffffffffffff811115611d4a57600080fd5b611d5684828501611aec565b604083015250606082013567ffffffffffffffff811115611d7657600080fd5b611d8284828501611b6f565b6060830152506080611d9684828501611e46565b60808301525092915050565b600060808284031215611db457600080fd5b611dbe6080612e0f565b90506000611dce84828501611ad7565b6000830152506020611de284828501611e46565b602083015250604082013567ffffffffffffffff811115611e0257600080fd5b611e0e84828501611aec565b604083015250606082013567ffffffffffffffff811115611e2e57600080fd5b611e3a84828501611b6f565b60608301525092915050565b600081359050611e558161313a565b92915050565b600060208284031215611e6d57600080fd5b6000611e7b84828501611ad7565b91505092915050565b600080600060608486031215611e9957600080fd5b6000611ea786828701611ad7565b935050602084013567ffffffffffffffff811115611ec457600080fd5b611ed086828701611aec565b925050604084013567ffffffffffffffff811115611eed57600080fd5b611ef986828701611b6f565b9150509250925092565b600080600080600060a08688031215611f1b57600080fd5b6000611f2988828901611ad7565b9550506020611f3a88828901611e46565b945050604086013567ffffffffffffffff811115611f5757600080fd5b611f6388828901611aec565b935050606086013567ffffffffffffffff811115611f8057600080fd5b611f8c88828901611b6f565b925050608086013567ffffffffffffffff811115611fa957600080fd5b611fb588828901611c6c565b9150509295509295909350565b60008060408385031215611fd557600080fd5b600083013567ffffffffffffffff811115611fef57600080fd5b611ffb85828601611aec565b925050602083013567ffffffffffffffff81111561201857600080fd5b61202485828601611b6f565b9150509250929050565b6000806040838503121561204157600080fd5b600083013567ffffffffffffffff81111561205b57600080fd5b61206785828601611b6f565b925050602061207885828601611be3565b9150509250929050565b60006020828403121561209457600080fd5b60006120a284828501611bf8565b91505092915050565b6000806000604084860312156120c057600080fd5b60006120ce86828701611c0d565b935050602084013567ffffffffffffffff8111156120eb57600080fd5b6120f786828701611c22565b92509250509250925092565b6000806040838503121561211657600080fd5b600061212485828601611cc0565b925050602061213585828601611cd5565b9150509250929050565b60006020828403121561215157600080fd5b600082013567ffffffffffffffff81111561216b57600080fd5b61217784828501611cea565b91505092915050565b60006020828403121561219257600080fd5b600082013567ffffffffffffffff8111156121ac57600080fd5b6121b884828501611da2565b91505092915050565b60006121cd83836121f7565b60208301905092915050565b6121e281612fb1565b82525050565b6121f181612f2e565b82525050565b61220081612f2e565b82525050565b61221761221282612f2e565b613071565b82525050565b600061222882612ec8565b6122328185612eeb565b935061223d83612eb8565b8060005b8381101561226e57815161225588826121c1565b975061226083612ede565b925050600181019050612241565b5085935050505092915050565b61228481612f40565b82525050565b61229381612f4c565b82525050565b6122aa6122a582612f4c565b613083565b82525050565b60006122bb82612ed3565b6122c58185612ef6565b93506122d581856020860161303e565b6122de816130a9565b840191505092915050565b60006122f482612ed3565b6122fe8185612f07565b935061230e81856020860161303e565b80840191505092915050565b61232381612fc3565b82525050565b61233281612fe7565b82525050565b6000612345601b83612f12565b91507f476174657761793a2063616e6e6f742073656e6420746f2030783000000000006000830152602082019050919050565b6000612385601c83612f23565b91507f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000830152601c82019050919050565b60006123c5602083612f12565b91507f477561726465643a2063616e6e6f74206164642030783020677561726469616e6000830152602082019050919050565b6000612405602f83612f12565b91507f496e697469616c697a61626c653a2074782e6f726967696e206973206e6f742060008301527f74686520696e697469616c697a657200000000000000000000000000000000006020830152604082019050919050565b600061246b601783612f12565b91507f476174657761793a2062617463682072657665727465640000000000000000006000830152602082019050919050565b60006124ab603283612f12565b91507f476174657761793a206e6f6e6365206973206c6f776572207468616e2063757260008301527f72656e74206163636f756e74206e6f6e636500000000000000000000000000006020830152604082019050919050565b6000612511602583612f12565b91507f476174657761793a2063616e6e6f742073656e642066726f6d2030783020616360008301527f636f756e740000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612577602683612f12565b91507f476174657761793a2063616e6e6f742064656c656761746520656d707479206260008301527f61746368657300000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006125dd602883612f12565b91507f476174657761793a2073656e646572206973206e6f7420746865206163636f7560008301527f6e74206f776e65720000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612643601683612f12565b91507f476174657761793a20696e76616c6964206261746368000000000000000000006000830152602082019050919050565b6000612683602683612f12565b91507f477561726465643a2074782e6f726967696e206973206e6f742074686520677560008301527f61726469616e00000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006126e9601f83612f12565b91507f477561726465643a20677561726469616e20646f65736e2774206578697374006000830152602082019050919050565b6000612729602383612f12565b91507f476174657761793a206261746368207472616e73616374696f6e20726576657260008301527f74656400000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b600061278f601e83612f12565b91507f536166654d6174684c69623a206164646974696f6e206f766572666c6f7700006000830152602082019050919050565b60006127cf602083612f12565b91507f477561726465643a20677561726469616e20616c7265616479206578697374736000830152602082019050919050565b600061280f602083612f12565b91507f476174657761793a2063616e6e6f742073656e6420656d7074792062617463686000830152602082019050919050565b600061284f601b83612f12565b91507f477561726465643a2063616e6e6f742072656d6f76652073656c6600000000006000830152602082019050919050565b600061288f601d83612f12565b91507f476174657761793a20616c6c20626174636865732072657665727465640000006000830152602082019050919050565b6128cb81612f9a565b82525050565b6128e26128dd82612f9a565b61309f565b82525050565b6128f181612fa4565b82525050565b60006129038287612206565b60148201915061291382866128d1565b602082019150612923828561221d565b915061292f82846122e9565b915081905095945050505050565b60006129498288612206565b60148201915061295982876128d1565b602082019150612969828661221d565b915061297582856122e9565b915061298182846128d1565b6020820191508190509695505050505050565b60006129a082846122e9565b915081905092915050565b60006129b782866122e9565b91506129c38285612206565b6014820191506129d38284612206565b601482019150819050949350505050565b60006129f082856122e9565b91506129fc82846122e9565b91508190509392505050565b6000612a1382612378565b9150612a1f8284612299565b60208201915081905092915050565b6000612a3a82876128d1565b602082019150612a4a8286612206565b601482019150612a5a8285612299565b602082019150612a6a82846122e9565b915081905095945050505050565b6000602082019050612a8d60008301846121d9565b92915050565b6000604082019050612aa860008301856121d9565b612ab560208301846121e8565b9392505050565b6000606082019050612ad160008301866121d9565b8181036020830152612ae381856122b0565b9050612af2604083018461227b565b949350505050565b6000604082019050612b0f60008301856121e8565b612b1c60208301846121e8565b9392505050565b6000602082019050612b38600083018461227b565b92915050565b6000602082019050612b53600083018461228a565b92915050565b6000608082019050612b6e600083018761228a565b612b7b60208301866128e8565b612b88604083018561228a565b612b95606083018461228a565b95945050505050565b6000602082019050612bb3600083018461231a565b92915050565b6000602082019050612bce6000830184612329565b92915050565b60006020820190508181036000830152612bed81612338565b9050919050565b60006020820190508181036000830152612c0d816123b8565b9050919050565b60006020820190508181036000830152612c2d816123f8565b9050919050565b60006020820190508181036000830152612c4d8161245e565b9050919050565b60006020820190508181036000830152612c6d8161249e565b9050919050565b60006020820190508181036000830152612c8d81612504565b9050919050565b60006020820190508181036000830152612cad8161256a565b9050919050565b60006020820190508181036000830152612ccd816125d0565b9050919050565b60006020820190508181036000830152612ced81612636565b9050919050565b60006020820190508181036000830152612d0d81612676565b9050919050565b60006020820190508181036000830152612d2d816126dc565b9050919050565b60006020820190508181036000830152612d4d8161271c565b9050919050565b60006020820190508181036000830152612d6d81612782565b9050919050565b60006020820190508181036000830152612d8d816127c2565b9050919050565b60006020820190508181036000830152612dad81612802565b9050919050565b60006020820190508181036000830152612dcd81612842565b9050919050565b60006020820190508181036000830152612ded81612882565b9050919050565b6000602082019050612e0960008301846128c2565b92915050565b6000604051905081810181811067ffffffffffffffff82111715612e3257600080fd5b8060405250919050565b600067ffffffffffffffff821115612e5357600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612e7b57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612ea357600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000612f3982612f7a565b9050919050565b60008115159050919050565b6000819050919050565b6000612f6182612f2e565b9050919050565b6000612f7382612f2e565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000612fbc8261300b565b9050919050565b6000612fce82612fd5565b9050919050565b6000612fe082612f7a565b9050919050565b6000612ff282612ff9565b9050919050565b600061300482612f7a565b9050919050565b60006130168261301d565b9050919050565b600061302882612f7a565b9050919050565b82818337600083830152505050565b60005b8381101561305c578082015181840152602081019050613041565b8381111561306b576000848401525b50505050565b600061307c8261308d565b9050919050565b6000819050919050565b6000613098826130ba565b9050919050565b6000819050919050565b6000601f19601f8301169050919050565b60008160601b9050919050565b6130d081612f2e565b81146130db57600080fd5b50565b6130e781612f40565b81146130f257600080fd5b50565b6130fe81612f4c565b811461310957600080fd5b50565b61311581612f56565b811461312057600080fd5b50565b61312c81612f68565b811461313757600080fd5b50565b61314381612f9a565b811461314e57600080fd5b5056fea164736f6c634300060c000a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101425760003560e01c806387d31313116100b8578063b5021b161161007c578063b5021b1614610349578063d0f710d614610365578063d2c83b9a14610395578063d305d0db146103b3578063d9f13021146103cf578063f92c5f7c146103eb57610142565b806387d31313146102b95780639a8a0592146102d75780639f255626146102f5578063a526d83b14610311578063ac2a08cd1461032d57610142565b8063538901341161010a57806353890134146101e95780635afaa7bb14610205578063714041561461022157806373e5a13f1461023d57806376db2b4c1461026d578063867519c61461029d57610142565b80630c68ba2114610147578063231badaf14610177578063371aa71a14610193578063392e53cd146101af578063485cc955146101cd575b600080fd5b610161600480360381019061015c9190611e5b565b61041b565b60405161016e9190612b23565b60405180910390f35b610191600480360381019061018c9190611f03565b610471565b005b6101ad60048036038101906101a89190611f03565b61056c565b005b6101b761060c565b6040516101c49190612b23565b60405180910390f35b6101e760048036038101906101e29190612103565b610662565b005b61020360048036038101906101fe9190611fc2565b6107fa565b005b61021f600480360381019061021a919061202e565b610894565b005b61023b60048036038101906102369190611e5b565b610a6c565b005b61025760048036038101906102529190612180565b610c87565b6040516102649190612b3e565b60405180910390f35b6102876004803603810190610282919061213f565b610cac565b6040516102949190612b3e565b60405180910390f35b6102b760048036038101906102b29190611e84565b610cd6565b005b6102c1610ce7565b6040516102ce9190612bb9565b60405180910390f35b6102df610d0d565b6040516102ec9190612df4565b60405180910390f35b61030f600480360381019061030a9190611fc2565b610d13565b005b61032b60048036038101906103269190611e5b565b610d23565b005b61034760048036038101906103429190611f03565b610dbb565b005b610363600480360381019061035e9190611f03565b610e5b565b005b61037f600480360381019061037a91906120ab565b610f57565b60405161038c9190612b23565b60405180910390f35b61039d610fb0565b6040516103aa9190612b9e565b60405180910390f35b6103cd60048036038101906103c89190611e84565b610fd6565b005b6103e960048036038101906103e4919061202e565b611072565b005b61040560048036038101906104009190611e5b565b61110c565b6040516104129190612df4565b60405180910390f35b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484116104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e990612c54565b60405180910390fd5b60006105128261050488888888611168565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061056486828686611286565b505050505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166105f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ef90612cf4565b60405180910390fd5b6106058585858585610e5b565b5050505050565b60008073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e790612c14565b60405180910390fd5b60008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060606107be816116f1565b507f908408e307fc569b417f6cbec5d5a06f44a0a505ac0479b47d421a4b2fd6a1e6326040516107ee9190612a78565b60405180910390a15050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161087d90612cf4565b60405180910390fd5b6108908282610d13565b5050565b60008251116108d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108cf90612c94565b60405180910390fd5b600080600090505b8351811015610a265760003073ffffffffffffffffffffffffffffffffffffffff1685838151811061090e57fe5b60200260200101516040516109239190612994565b6000604051808303816000865af19150503d8060008114610960576040519150601f19603f3d011682016040523d82523d6000602084013e610965565b606091505b5050905083156109b457806109af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a690612c34565b60405180910390fd5b6109ca565b8080156109bf575082155b156109c957600192505b5b7f361c14722cc344132c73396113f7164232448b09c544a149f09048648b43d872338684815181106109f857fe5b602002602001015183604051610a1093929190612abc565b60405180910390a15080806001019150506108e0565b5080610a67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5e90612dd4565b60405180910390fd5b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610af8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aef90612cf4565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff161415610b67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5e90612db4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610bf3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bea90612d14565b60405180910390fd5b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fee943cdb81826d5909c559c6b1ae6908fcaf2dbc16c4b730346736b486283e8b3282604051610c7c929190612a93565b60405180910390a150565b6000610ca58260000151836020015184604001518560600151611168565b9050919050565b6000610ccf82600001518360200151846040015185606001518660800151611749565b9050919050565b610ce283338484611286565b505050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b610d1f33338484611286565b5050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610daf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610da690612cf4565b60405180910390fd5b610db8816117af565b50565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610e47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3e90612cf4565b60405180910390fd5b610e548585858585610471565b5050505050565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548411610edc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ed390612c54565b60405180910390fd5b6000610efd82610eef888888883a611749565b6111cb90919063ffffffff16565b905084600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610f4f86828686611286565b505050505050565b6000610fa78484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611940565b90509392505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611062576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105990612cf4565b60405180910390fd5b61106d838383610cd6565b505050565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166110fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110f590612cf4565b60405180910390fd5b6111088282610894565b5050565b60006111616001600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546119ae90919063ffffffff16565b9050919050565b60006111c17f6848d0622081db2451400280dead7a739a080cb93852607c381af11e289769b286868661119a87611a03565b6040516020016111ad94939291906128f7565b604051602081830303815290604052611a66565b9050949350505050565b6000806000905060418351141561127c5760008060006020860151925060408601519150606086015160001a9050601b8160ff16101561120c57601b810190505b601b8160ff1614806112215750601c8160ff16145b1561127857600187828585604051600081526020016040526040516112499493929190612b59565b6020604051602081039080840390855afa15801561126b573d6000803e3d6000fd5b5050506020604051035193505b5050505b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156112f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ed90612c74565b60405180910390fd5b600082511161133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161133190612d94565b60405180910390fd5b815181511461137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137590612cd4565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461155257600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b815260040161140e929190612afa565b60206040518083038186803b15801561142657600080fd5b505afa15801561143a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145e9190612082565b806115125750600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb890d3f85856040518363ffffffff1660e01b81526004016114c1929190612afa565b60206040518083038186803b1580156114d957600080fd5b505afa1580156114ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115119190612082565b5b611551576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161154890612cb4565b60405180910390fd5b5b600080600090505b82518110156116e957600073ffffffffffffffffffffffffffffffffffffffff1684828151811061158757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614156115e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115dd90612bd4565b60405180910390fd5b8381815181106115f257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1683828151811061161c57fe5b60200260200101518787604051602001611638939291906129ab565b6040516020818303038152906040526040516116549190612994565b6000604051808303816000865af19150503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b505080925050816116dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d390612d34565b60405180910390fd5b808060010191505061155a565b505050505050565b60008151141561170957611704326117af565b611746565b60008151905060005b818110156117435761173683828151811061172957fe5b60200260200101516117af565b8080600101915050611712565b50505b50565b60006117a47f6f4e1b2b1e5e49f4269e19e16e67a00cb0a796d96d30be3e4b540d3732e8bcad87878761177b88611a03565b8760405160200161179095949392919061293d565b604051602081830303815290604052611a66565b905095945050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561181f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161181690612bf4565b60405180910390fd5b600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156118ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a390612d74565b60405180910390fd5b6001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a3282604051611935929190612a93565b60405180910390a150565b60008061195683856111cb90919063ffffffff16565b9050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1691505092915050565b6000808284019050838110156119f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f090612d54565b60405180910390fd5b8091505092915050565b60608060008351905060005b81811015611a5b5782858281518110611a2457fe5b6020026020010151604051602001611a3d9291906129e4565b60405160208183030381529060405292508080600101915050611a0f565b508192505050919050565b6000611a9f600154308585604051602001611a849493929190612a2e565b60405160208183030381529060405280519060200120611aa7565b905092915050565b600081604051602001611aba9190612a08565b604051602081830303815290604052805190602001209050919050565b600081359050611ae6816130c7565b92915050565b600082601f830112611afd57600080fd5b8135611b10611b0b82612e3c565b612e0f565b91508181835260208401935060208101905083856020840282011115611b3557600080fd5b60005b83811015611b655781611b4b8882611ad7565b845260208401935060208301925050600181019050611b38565b5050505092915050565b600082601f830112611b8057600080fd5b8135611b93611b8e82612e64565b612e0f565b9150818183526020840193506020810190508360005b83811015611bd95781358601611bbf8882611c6c565b845260208401935060208301925050600181019050611ba9565b5050505092915050565b600081359050611bf2816130de565b92915050565b600081519050611c07816130de565b92915050565b600081359050611c1c816130f5565b92915050565b60008083601f840112611c3457600080fd5b8235905067ffffffffffffffff811115611c4d57600080fd5b602083019150836001820283011115611c6557600080fd5b9250929050565b600082601f830112611c7d57600080fd5b8135611c90611c8b82612e8c565b612e0f565b91508082526020830160208301858383011115611cac57600080fd5b611cb783828461302f565b50505092915050565b600081359050611ccf8161310c565b92915050565b600081359050611ce481613123565b92915050565b600060a08284031215611cfc57600080fd5b611d0660a0612e0f565b90506000611d1684828501611ad7565b6000830152506020611d2a84828501611e46565b602083015250604082013567ffffffffffffffff811115611d4a57600080fd5b611d5684828501611aec565b604083015250606082013567ffffffffffffffff811115611d7657600080fd5b611d8284828501611b6f565b6060830152506080611d9684828501611e46565b60808301525092915050565b600060808284031215611db457600080fd5b611dbe6080612e0f565b90506000611dce84828501611ad7565b6000830152506020611de284828501611e46565b602083015250604082013567ffffffffffffffff811115611e0257600080fd5b611e0e84828501611aec565b604083015250606082013567ffffffffffffffff811115611e2e57600080fd5b611e3a84828501611b6f565b60608301525092915050565b600081359050611e558161313a565b92915050565b600060208284031215611e6d57600080fd5b6000611e7b84828501611ad7565b91505092915050565b600080600060608486031215611e9957600080fd5b6000611ea786828701611ad7565b935050602084013567ffffffffffffffff811115611ec457600080fd5b611ed086828701611aec565b925050604084013567ffffffffffffffff811115611eed57600080fd5b611ef986828701611b6f565b9150509250925092565b600080600080600060a08688031215611f1b57600080fd5b6000611f2988828901611ad7565b9550506020611f3a88828901611e46565b945050604086013567ffffffffffffffff811115611f5757600080fd5b611f6388828901611aec565b935050606086013567ffffffffffffffff811115611f8057600080fd5b611f8c88828901611b6f565b925050608086013567ffffffffffffffff811115611fa957600080fd5b611fb588828901611c6c565b9150509295509295909350565b60008060408385031215611fd557600080fd5b600083013567ffffffffffffffff811115611fef57600080fd5b611ffb85828601611aec565b925050602083013567ffffffffffffffff81111561201857600080fd5b61202485828601611b6f565b9150509250929050565b6000806040838503121561204157600080fd5b600083013567ffffffffffffffff81111561205b57600080fd5b61206785828601611b6f565b925050602061207885828601611be3565b9150509250929050565b60006020828403121561209457600080fd5b60006120a284828501611bf8565b91505092915050565b6000806000604084860312156120c057600080fd5b60006120ce86828701611c0d565b935050602084013567ffffffffffffffff8111156120eb57600080fd5b6120f786828701611c22565b92509250509250925092565b6000806040838503121561211657600080fd5b600061212485828601611cc0565b925050602061213585828601611cd5565b9150509250929050565b60006020828403121561215157600080fd5b600082013567ffffffffffffffff81111561216b57600080fd5b61217784828501611cea565b91505092915050565b60006020828403121561219257600080fd5b600082013567ffffffffffffffff8111156121ac57600080fd5b6121b884828501611da2565b91505092915050565b60006121cd83836121f7565b60208301905092915050565b6121e281612fb1565b82525050565b6121f181612f2e565b82525050565b61220081612f2e565b82525050565b61221761221282612f2e565b613071565b82525050565b600061222882612ec8565b6122328185612eeb565b935061223d83612eb8565b8060005b8381101561226e57815161225588826121c1565b975061226083612ede565b925050600181019050612241565b5085935050505092915050565b61228481612f40565b82525050565b61229381612f4c565b82525050565b6122aa6122a582612f4c565b613083565b82525050565b60006122bb82612ed3565b6122c58185612ef6565b93506122d581856020860161303e565b6122de816130a9565b840191505092915050565b60006122f482612ed3565b6122fe8185612f07565b935061230e81856020860161303e565b80840191505092915050565b61232381612fc3565b82525050565b61233281612fe7565b82525050565b6000612345601b83612f12565b91507f476174657761793a2063616e6e6f742073656e6420746f2030783000000000006000830152602082019050919050565b6000612385601c83612f23565b91507f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000830152601c82019050919050565b60006123c5602083612f12565b91507f477561726465643a2063616e6e6f74206164642030783020677561726469616e6000830152602082019050919050565b6000612405602f83612f12565b91507f496e697469616c697a61626c653a2074782e6f726967696e206973206e6f742060008301527f74686520696e697469616c697a657200000000000000000000000000000000006020830152604082019050919050565b600061246b601783612f12565b91507f476174657761793a2062617463682072657665727465640000000000000000006000830152602082019050919050565b60006124ab603283612f12565b91507f476174657761793a206e6f6e6365206973206c6f776572207468616e2063757260008301527f72656e74206163636f756e74206e6f6e636500000000000000000000000000006020830152604082019050919050565b6000612511602583612f12565b91507f476174657761793a2063616e6e6f742073656e642066726f6d2030783020616360008301527f636f756e740000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612577602683612f12565b91507f476174657761793a2063616e6e6f742064656c656761746520656d707479206260008301527f61746368657300000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006125dd602883612f12565b91507f476174657761793a2073656e646572206973206e6f7420746865206163636f7560008301527f6e74206f776e65720000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612643601683612f12565b91507f476174657761793a20696e76616c6964206261746368000000000000000000006000830152602082019050919050565b6000612683602683612f12565b91507f477561726465643a2074782e6f726967696e206973206e6f742074686520677560008301527f61726469616e00000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006126e9601f83612f12565b91507f477561726465643a20677561726469616e20646f65736e2774206578697374006000830152602082019050919050565b6000612729602383612f12565b91507f476174657761793a206261746368207472616e73616374696f6e20726576657260008301527f74656400000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b600061278f601e83612f12565b91507f536166654d6174684c69623a206164646974696f6e206f766572666c6f7700006000830152602082019050919050565b60006127cf602083612f12565b91507f477561726465643a20677561726469616e20616c7265616479206578697374736000830152602082019050919050565b600061280f602083612f12565b91507f476174657761793a2063616e6e6f742073656e6420656d7074792062617463686000830152602082019050919050565b600061284f601b83612f12565b91507f477561726465643a2063616e6e6f742072656d6f76652073656c6600000000006000830152602082019050919050565b600061288f601d83612f12565b91507f476174657761793a20616c6c20626174636865732072657665727465640000006000830152602082019050919050565b6128cb81612f9a565b82525050565b6128e26128dd82612f9a565b61309f565b82525050565b6128f181612fa4565b82525050565b60006129038287612206565b60148201915061291382866128d1565b602082019150612923828561221d565b915061292f82846122e9565b915081905095945050505050565b60006129498288612206565b60148201915061295982876128d1565b602082019150612969828661221d565b915061297582856122e9565b915061298182846128d1565b6020820191508190509695505050505050565b60006129a082846122e9565b915081905092915050565b60006129b782866122e9565b91506129c38285612206565b6014820191506129d38284612206565b601482019150819050949350505050565b60006129f082856122e9565b91506129fc82846122e9565b91508190509392505050565b6000612a1382612378565b9150612a1f8284612299565b60208201915081905092915050565b6000612a3a82876128d1565b602082019150612a4a8286612206565b601482019150612a5a8285612299565b602082019150612a6a82846122e9565b915081905095945050505050565b6000602082019050612a8d60008301846121d9565b92915050565b6000604082019050612aa860008301856121d9565b612ab560208301846121e8565b9392505050565b6000606082019050612ad160008301866121d9565b8181036020830152612ae381856122b0565b9050612af2604083018461227b565b949350505050565b6000604082019050612b0f60008301856121e8565b612b1c60208301846121e8565b9392505050565b6000602082019050612b38600083018461227b565b92915050565b6000602082019050612b53600083018461228a565b92915050565b6000608082019050612b6e600083018761228a565b612b7b60208301866128e8565b612b88604083018561228a565b612b95606083018461228a565b95945050505050565b6000602082019050612bb3600083018461231a565b92915050565b6000602082019050612bce6000830184612329565b92915050565b60006020820190508181036000830152612bed81612338565b9050919050565b60006020820190508181036000830152612c0d816123b8565b9050919050565b60006020820190508181036000830152612c2d816123f8565b9050919050565b60006020820190508181036000830152612c4d8161245e565b9050919050565b60006020820190508181036000830152612c6d8161249e565b9050919050565b60006020820190508181036000830152612c8d81612504565b9050919050565b60006020820190508181036000830152612cad8161256a565b9050919050565b60006020820190508181036000830152612ccd816125d0565b9050919050565b60006020820190508181036000830152612ced81612636565b9050919050565b60006020820190508181036000830152612d0d81612676565b9050919050565b60006020820190508181036000830152612d2d816126dc565b9050919050565b60006020820190508181036000830152612d4d8161271c565b9050919050565b60006020820190508181036000830152612d6d81612782565b9050919050565b60006020820190508181036000830152612d8d816127c2565b9050919050565b60006020820190508181036000830152612dad81612802565b9050919050565b60006020820190508181036000830152612dcd81612842565b9050919050565b60006020820190508181036000830152612ded81612882565b9050919050565b6000602082019050612e0960008301846128c2565b92915050565b6000604051905081810181811067ffffffffffffffff82111715612e3257600080fd5b8060405250919050565b600067ffffffffffffffff821115612e5357600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612e7b57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612ea357600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000612f3982612f7a565b9050919050565b60008115159050919050565b6000819050919050565b6000612f6182612f2e565b9050919050565b6000612f7382612f2e565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b6000612fbc8261300b565b9050919050565b6000612fce82612fd5565b9050919050565b6000612fe082612f7a565b9050919050565b6000612ff282612ff9565b9050919050565b600061300482612f7a565b9050919050565b60006130168261301d565b9050919050565b600061302882612f7a565b9050919050565b82818337600083830152505050565b60005b8381101561305c578082015181840152602081019050613041565b8381111561306b576000848401525b50505050565b600061307c8261308d565b9050919050565b6000819050919050565b6000613098826130ba565b9050919050565b6000819050919050565b6000601f19601f8301169050919050565b60008160601b9050919050565b6130d081612f2e565b81146130db57600080fd5b50565b6130e781612f40565b81146130f257600080fd5b50565b6130fe81612f4c565b811461310957600080fd5b50565b61311581612f56565b811461312057600080fd5b50565b61312c81612f68565b811461313757600080fd5b50565b61314381612f9a565b811461314e57600080fd5b5056fea164736f6c634300060c000a", + "devdoc": { + "author": "Utkir Sobirov ", + "events": { + "BatchDelegated(address,bytes,bool)": { + "details": "Emitted when the single batch is delegated", + "params": { + "batch": "batch", + "sender": "sender address", + "succeeded": "if succeeded" + } + } + }, + "kind": "dev", + "methods": { + "addGuardian(address)": { + "params": { + "guardian": "guardian address" + } + }, + "constructor": { + "details": "Public constructor" + }, + "delegateBatch(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatchGuarded(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatch` to create sender message payload. `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)": { + "details": "Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice) `GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return recovered address from `senderSignature` arg", + "params": { + "account": "account address", + "data": "array of batch data", + "nonce": "next account nonce", + "senderSignature": "sender signature", + "to": "array of batch recipients contracts" + } + }, + "delegateBatches(bytes[],bool)": { + "details": "It will revert when all batches fail", + "params": { + "batches": "array of batches", + "revertOnFailure": "reverts on any error" + } + }, + "delegateBatchesGuarded(bytes[],bool)": { + "details": "It will revert when all batches fail", + "params": { + "batches": "array of batches", + "revertOnFailure": "reverts on any error" + } + }, + "getAccountNextNonce(address)": { + "params": { + "account": "account address" + }, + "returns": { + "_0": "next nonce" + } + }, + "hashDelegatedBatch((address,uint256,address[],bytes[]))": { + "params": { + "delegatedBatch": "struct" + }, + "returns": { + "_0": "hash" + } + }, + "hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))": { + "params": { + "delegatedBatch": "struct" + }, + "returns": { + "_0": "hash" + } + }, + "initialize(address,address)": { + "params": { + "externalAccountRegistry_": "`ExternalAccountRegistry` contract address", + "personalAccountRegistry_": "`PersonalAccountRegistry` contract address" + } + }, + "isGuardian(address)": { + "params": { + "guardian": "guardian address" + }, + "returns": { + "_0": "true when guardian exists" + } + }, + "isInitialized()": { + "returns": { + "_0": "true when contract is initialized" + } + }, + "removeGuardian(address)": { + "params": { + "guardian": "guardian address" + } + }, + "sendBatch(address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`", + "params": { + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "sendBatchFromAccount(address,address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`", + "params": { + "account": "account address", + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "sendBatchFromAccountGuarded(address,address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `account` arg `_getContextSender` will return `msg.sender`", + "params": { + "account": "account address", + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "sendBatchGuarded(address[],bytes[])": { + "details": "`GatewayRecipient` context api: `_getContextAccount` will return `msg.sender` `_getContextSender` will return `msg.sender`", + "params": { + "data": "array of batch data", + "to": "array of batch recipients contracts" + } + }, + "verifyGuardianSignature(bytes32,bytes)": { + "params": { + "messageHash": "message hash", + "signature": "signature" + }, + "returns": { + "_0": "true on correct guardian signature" + } + } + }, + "title": "Gateway V2 with guarded batching functions", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "addGuardian(address)": { + "notice": "Adds a new guardian" + }, + "delegateBatch(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates batch from the account" + }, + "delegateBatchGuarded(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates guarded batch from the account" + }, + "delegateBatchWithGasPrice(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates batch from the account (with gas price)" + }, + "delegateBatchWithGasPriceGuarded(address,uint256,address[],bytes[],bytes)": { + "notice": "Delegates guarded batch from the account (with gas price)" + }, + "delegateBatches(bytes[],bool)": { + "notice": "Delegates multiple batches" + }, + "delegateBatchesGuarded(bytes[],bool)": { + "notice": "Delegates multiple guarded batches" + }, + "getAccountNextNonce(address)": { + "notice": "Gets next account nonce" + }, + "hashDelegatedBatch((address,uint256,address[],bytes[]))": { + "notice": "Hashes `DelegatedBatch` message payload" + }, + "hashDelegatedBatchWithGasPrice((address,uint256,address[],bytes[],uint256))": { + "notice": "Hashes `DelegatedBatchWithGasPrice` message payload" + }, + "initialize(address,address)": { + "notice": "Initializes `Gateway` contract" + }, + "isGuardian(address)": { + "notice": "Check if guardian exists" + }, + "isInitialized()": { + "notice": "Check if contract is initialized" + }, + "removeGuardian(address)": { + "notice": "Removes the existing guardian" + }, + "sendBatch(address[],bytes[])": { + "notice": "Sends batch" + }, + "sendBatchFromAccount(address,address[],bytes[])": { + "notice": "Sends batch from the account" + }, + "sendBatchFromAccountGuarded(address,address[],bytes[])": { + "notice": "Sends guarded batch from the account" + }, + "sendBatchGuarded(address[],bytes[])": { + "notice": "Sends guarded batch" + }, + "verifyGuardianSignature(bytes32,bytes)": { + "notice": "Verifies guardian signature" + } + }, + "notice": "GSN replacement", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1227, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "initializer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 1291, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "chainId", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 40, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "guardians", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 2826, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "externalAccountRegistry", + "offset": 0, + "slot": "3", + "type": "t_contract(ExternalAccountRegistry)2009" + }, + { + "astId": 2828, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "personalAccountRegistry", + "offset": 0, + "slot": "4", + "type": "t_contract(PersonalAccountRegistry)4188" + }, + { + "astId": 2832, + "contract": "src/gateway/GatewayV2.sol:GatewayV2", + "label": "accountNonce", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_address,t_uint256)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(ExternalAccountRegistry)2009": { + "encoding": "inplace", + "label": "contract ExternalAccountRegistry", + "numberOfBytes": "20" + }, + "t_contract(PersonalAccountRegistry)4188": { + "encoding": "inplace", + "label": "contract PersonalAccountRegistry", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/matic/solcInputs/8f6f179d2c9d29fd59e34814c3f7994c.json b/deployments/matic/solcInputs/8f6f179d2c9d29fd59e34814c3f7994c.json new file mode 100644 index 00000000..29b6e22f --- /dev/null +++ b/deployments/matic/solcInputs/8f6f179d2c9d29fd59e34814c3f7994c.json @@ -0,0 +1,94 @@ +{ + "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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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" + ] + } + } + } +} \ No newline at end of file diff --git a/dist/contracts.js b/dist/contracts.js index a9d1ddf5..0e59aa4c 100644 --- a/dist/contracts.js +++ b/dist/contracts.js @@ -6492,14 +6492,14 @@ module.exports = { "5": "0xBEd52610518788B931f7825301909e7616273d47", "10": null, "42": null, - "56": null, + "56": "0xBEd52610518788B931f7825301909e7616273d47", "69": null, "77": "0xBEd52610518788B931f7825301909e7616273d47", "97": "0xBEd52610518788B931f7825301909e7616273d47", "100": null, "122": null, "123": null, - "137": null, + "137": "0xBEd52610518788B931f7825301909e7616273d47", "250": null, "1284": null, "1287": null, diff --git a/package-lock.json b/package-lock.json index fb79c3f2..883081cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@etherspot/contracts", - "version": "1.9.2", + "version": "1.9.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@etherspot/contracts", - "version": "1.9.2", + "version": "1.9.3", "license": "MIT", "devDependencies": { "@connext/nxtp-contracts": "0.2.0-beta.20", diff --git a/package.json b/package.json index de1a3f08..871d2e9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@etherspot/contracts", - "version": "1.9.2", + "version": "1.9.3", "description": "Etherspot Solidity contracts", "keywords": [ "ether",