Evmos vulnerable to exploit of smart contract account and vesting
Description
Evmos is a decentralized Ethereum Virtual Machine chain on the Cosmos Network. Prior to version 19.0.0, a user can create a vesting account with a 3rd party account (EOA or contract) as funder. Then, this user can create an authorization for the contract.CallerAddress, this is the authorization checked in the code. But the funds are taken from the funder address provided in the message. Consequently, the user can fund a vesting account with a 3rd party account without its permission. The funder address can be any address, so this vulnerability can be used to drain all the accounts in the chain. The issue has been patched in version 19.0.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2024-39696 allows an attacker to drain any account on the Evmos blockchain by exploiting a flaw in vesting account creation that bypasses funder authorization.
Vulnerability
Description
CVE-2024-39696 is a critical authorization bypass vulnerability in the Evmos blockchain, a Cosmos-based Ethereum Virtual Machine chain. The issue resides in the fundVestingAccount precompile: a user can create a vesting account specifying any address as the funder, without that address's consent. The authorization check in the code only verifies the caller's authorization for a contract.CallerAddress, but the actual funds are debited from the arbitrary funder address provided in the message [1][4].
Exploitation
An attacker can exploit this by first creating a vesting account with a target victim's address as the funder. Then, the attacker creates an authorization for the contract.CallerAddress (which may be their own contract). Because the authorization check does not verify that the caller is the funder, the transaction proceeds and deducts funds from the victim's address. Since the funder field can be any address on the chain, the vulnerability effectively allows an attacker to drain any account without permission [4].
Impact
This flaw could lead to a complete loss of funds for any account on the Evmos chain. The advisory rates the severity as Critical under the ImmuneFi Severity Classification System, as it enables direct fund theft without any prerequisite other than submitting a crafted transaction [4].
Mitigation
The vulnerability has been patched in Evmos version 19.0.0 and later. Users are strongly advised to upgrade immediately to protect their assets [1][4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/evmos/evmos/v18Go | < 19.0.0 | 19.0.0 |
Affected products
3Patches
22228348af5c60a620e176617Merge pull request from GHSA-q6hg-6m9x-5g9c
15 files changed · +1668 −178
precompiles/testutil/contracts/counter.go+13 −0 added@@ -0,0 +1,13 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package contracts + +import ( + contractutils "github.com/evmos/evmos/v18/contracts/utils" + evmtypes "github.com/evmos/evmos/v18/x/evm/types" +) + +func LoadCounterContract() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("Counter.json") +}
precompiles/testutil/contracts/Counter.json+64 −0 added@@ -0,0 +1,64 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "Counter", + "sourceName": "solidity/precompiles/testutil/contracts/Counter.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "counter", + "type": "uint256" + } + ], + "name": "Added", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "counter", + "type": "uint256" + } + ], + "name": "Changed", + "type": "event" + }, + { + "inputs": [], + "name": "add", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCounter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "subtract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040526000805534801561001457600080fd5b50610397806100246000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80634f2be91f146100465780636deebae3146100505780638ada066e1461005a575b600080fd5b61004e610078565b005b610058610103565b005b6100626101d2565b60405161006f91906101f4565b60405180910390f35b60008081548092919061008a9061023e565b91905055507f64a55044d1f2eddebe1b90e8e2853e8e96931cefadbfa0b2ceb34bee360619416000546040516100c091906101f4565b60405180910390a17f938d2ee5be9cfb0f7270ee2eff90507e94b37625d9d2b3a61c97d30a4560b8296000546040516100f991906101f4565b60405180910390a1565b60008054116040518060400160405280600f81526020017f434f554e5445525f544f4f5f4c4f5700000000000000000000000000000000008152509061017f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101769190610316565b60405180910390fd5b5060008081548092919061019290610338565b91905055507f938d2ee5be9cfb0f7270ee2eff90507e94b37625d9d2b3a61c97d30a4560b8296000546040516101c891906101f4565b60405180910390a1565b60008054905090565b6000819050919050565b6101ee816101db565b82525050565b600060208201905061020960008301846101e5565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610249826101db565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361027b5761027a61020f565b5b600182019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156102c05780820151818401526020810190506102a5565b60008484015250505050565b6000601f19601f8301169050919050565b60006102e882610286565b6102f28185610291565b93506103028185602086016102a2565b61030b816102cc565b840191505092915050565b6000602082019050818103600083015261033081846102dd565b905092915050565b6000610343826101db565b9150600082036103565761035561020f565b5b60018203905091905056fea26469706673582212202870b2d78304eb0ec6b95f72bacf96e449481ecaa4d58a3ce786c1cba532075d64736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80634f2be91f146100465780636deebae3146100505780638ada066e1461005a575b600080fd5b61004e610078565b005b610058610103565b005b6100626101d2565b60405161006f91906101f4565b60405180910390f35b60008081548092919061008a9061023e565b91905055507f64a55044d1f2eddebe1b90e8e2853e8e96931cefadbfa0b2ceb34bee360619416000546040516100c091906101f4565b60405180910390a17f938d2ee5be9cfb0f7270ee2eff90507e94b37625d9d2b3a61c97d30a4560b8296000546040516100f991906101f4565b60405180910390a1565b60008054116040518060400160405280600f81526020017f434f554e5445525f544f4f5f4c4f5700000000000000000000000000000000008152509061017f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101769190610316565b60405180910390fd5b5060008081548092919061019290610338565b91905055507f938d2ee5be9cfb0f7270ee2eff90507e94b37625d9d2b3a61c97d30a4560b8296000546040516101c891906101f4565b60405180910390a1565b60008054905090565b6000819050919050565b6101ee816101db565b82525050565b600060208201905061020960008301846101e5565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610249826101db565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361027b5761027a61020f565b5b600182019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156102c05780820151818401526020810190506102a5565b60008484015250505050565b6000601f19601f8301169050919050565b60006102e882610286565b6102f28185610291565b93506103028185602086016102a2565b61030b816102cc565b840191505092915050565b6000602082019050818103600083015261033081846102dd565b905092915050565b6000610343826101db565b9150600082036103565761035561020f565b5b60018203905091905056fea26469706673582212202870b2d78304eb0ec6b95f72bacf96e449481ecaa4d58a3ce786c1cba532075d64736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +}
precompiles/testutil/contracts/Counter.sol+26 −0 added@@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +contract Counter { + uint256 counter = 0; + string internal constant ERROR_TOO_LOW = "COUNTER_TOO_LOW"; + event Changed(uint256 counter); + event Added(uint256 counter); + + function add() public { + counter++; + emit Added(counter); + emit Changed(counter); + } + + function subtract() public { + require(counter > 0, ERROR_TOO_LOW); + counter--; + emit Changed(counter); + } + + function getCounter() public view returns (uint256) { + return counter; + } +}
precompiles/testutil/contracts/DistributionCaller.json+2 −2 modifiedprecompiles/testutil/contracts/FlashLoan.json+3 −3 modified@@ -1,7 +1,7 @@ { "_format": "hh-sol-artifact-1", "contractName": "FlashLoan", - "sourceName": "contracts/evmos/testutil/contracts/FlashLoan.sol", + "sourceName": "solidity/precompiles/testutil/contracts/FlashLoan.sol", "abi": [ { "inputs": [], @@ -103,8 +103,8 @@ "type": "function" } ], - "bytecode": "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506113ea806100606000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80638da5cb5b146100515780638f5184301461006f578063ee52ad711461008b578063f12fae93146100bb575b600080fd5b6100596100eb565b6040516100669190610bdd565b60405180910390f35b61008960048036038101906100849190610db4565b61010f565b005b6100a560048036038101906100a09190610db4565b6101da565b6040516100b29190610e3e565b60405180910390f35b6100d560048036038101906100d09190610db4565b6107c9565b6040516100e29190610e3e565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb8585856040518463ffffffff1660e01b815260040161015093929190610ee7565b6020604051808303816000875af115801561016f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101939190610f51565b9050806101d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101cc90610fca565b60405180910390fd5b600080fd5b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102629061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b81526004016102ac92919061107c565b602060405180830381865afa1580156102c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ed91906110ba565b101561032e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032590611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016103699190610bdd565b602060405180830381865afa158015610386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103aa91906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016103eb93929190611153565b6020604051808303816000875af115801561040a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042e9190610f51565b905080610470576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610467906111fc565b60405180910390fd5b848261047c919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016104b59190610bdd565b602060405180830381865afa1580156104d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f691906110ba565b14610536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052d906112cb565b60405180910390fd5b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3388886040518463ffffffff1660e01b815260040161057593929190610ee7565b6020604051808303816000875af1158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190610f51565b9050806105fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f190610fca565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016106339190610bdd565b602060405180830381865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067491906110ba565b91508273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33876040518363ffffffff1660e01b81526004016106b19291906112eb565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f49190610f51565b5084826107019190611314565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161073a9190610bdd565b602060405180830381865afa158015610757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077b91906110ba565b146107bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b290611394565b60405180910390fd5b600193505050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108519061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b815260040161089b92919061107c565b602060405180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc91906110ba565b101561091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091490611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109589190610bdd565b602060405180830381865afa158015610975573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099991906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016109da93929190611153565b6020604051808303816000875af11580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190610f51565b905080610a5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a56906111fc565b60405180910390fd5b8482610a6b919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610aa49190610bdd565b602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae591906110ba565b14610b25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1c906112cb565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16638f5184303388886040518463ffffffff1660e01b8152600401610b6293929190610ee7565b600060405180830381600087803b158015610b7c57600080fd5b505af1925050508015610b8d575060015b50600193505050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610bc782610b9c565b9050919050565b610bd781610bbc565b82525050565b6000602082019050610bf26000830184610bce565b92915050565b6000604051905090565b600080fd5b600080fd5b610c1581610bbc565b8114610c2057600080fd5b50565b600081359050610c3281610c0c565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610c8b82610c42565b810181811067ffffffffffffffff82111715610caa57610ca9610c53565b5b80604052505050565b6000610cbd610bf8565b9050610cc98282610c82565b919050565b600067ffffffffffffffff821115610ce957610ce8610c53565b5b610cf282610c42565b9050602081019050919050565b82818337600083830152505050565b6000610d21610d1c84610cce565b610cb3565b905082815260208101848484011115610d3d57610d3c610c3d565b5b610d48848285610cff565b509392505050565b600082601f830112610d6557610d64610c38565b5b8135610d75848260208601610d0e565b91505092915050565b6000819050919050565b610d9181610d7e565b8114610d9c57600080fd5b50565b600081359050610dae81610d88565b92915050565b600080600060608486031215610dcd57610dcc610c02565b5b6000610ddb86828701610c23565b935050602084013567ffffffffffffffff811115610dfc57610dfb610c07565b5b610e0886828701610d50565b9250506040610e1986828701610d9f565b9150509250925092565b60008115159050919050565b610e3881610e23565b82525050565b6000602082019050610e536000830184610e2f565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e93578082015181840152602081019050610e78565b60008484015250505050565b6000610eaa82610e59565b610eb48185610e64565b9350610ec4818560208601610e75565b610ecd81610c42565b840191505092915050565b610ee181610d7e565b82525050565b6000606082019050610efc6000830186610bce565b8181036020830152610f0e8185610e9f565b9050610f1d6040830184610ed8565b949350505050565b610f2e81610e23565b8114610f3957600080fd5b50565b600081519050610f4b81610f25565b92915050565b600060208284031215610f6757610f66610c02565b5b6000610f7584828501610f3c565b91505092915050565b7f6661696c656420746f2064656c65676174650000000000000000000000000000600082015250565b6000610fb4601283610e64565b9150610fbf82610f7e565b602082019050919050565b60006020820190508181036000830152610fe381610fa7565b9050919050565b7f4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f60008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b6000611046602183610e64565b915061105182610fea565b604082019050919050565b6000602082019050818103600083015261107581611039565b9050919050565b60006040820190506110916000830185610bce565b61109e6020830184610bce565b9392505050565b6000815190506110b481610d88565b92915050565b6000602082840312156110d0576110cf610c02565b5b60006110de848285016110a5565b91505092915050565b7f496e73756666696369656e7420616c6c6f77616e636500000000000000000000600082015250565b600061111d601683610e64565b9150611128826110e7565b602082019050919050565b6000602082019050818103600083015261114c81611110565b9050919050565b60006060820190506111686000830186610bce565b6111756020830185610bce565b6111826040830184610ed8565b949350505050565b7f4661696c656420746f207472616e7366657220746f6b656e7320666f7220666c60008201527f617368206c6f616e000000000000000000000000000000000000000000000000602082015250565b60006111e6602883610e64565b91506111f18261118a565b604082019050919050565b60006020820190508181036000830152611215816111d9565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061125682610d7e565b915061126183610d7e565b92508282019050808211156112795761127861121c565b5b92915050565b7f466c617368206c6f616e206661696c6564000000000000000000000000000000600082015250565b60006112b5601183610e64565b91506112c08261127f565b602082019050919050565b600060208201905081810360008301526112e4816112a8565b9050919050565b60006040820190506113006000830185610bce565b61130d6020830184610ed8565b9392505050565b600061131f82610d7e565b915061132a83610d7e565b92508282039050818111156113425761134161121c565b5b92915050565b7f466c617368206c6f616e2072657061796d656e74206661696c65640000000000600082015250565b600061137e601b83610e64565b915061138982611348565b602082019050919050565b600060208201905081810360008301526113ad81611371565b905091905056fea2646970667358221220c424c19551d9b4559d960ffe973aece9d88bd266c540f629abf8f11eb26a6c1e64736f6c63430008120033", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80638da5cb5b146100515780638f5184301461006f578063ee52ad711461008b578063f12fae93146100bb575b600080fd5b6100596100eb565b6040516100669190610bdd565b60405180910390f35b61008960048036038101906100849190610db4565b61010f565b005b6100a560048036038101906100a09190610db4565b6101da565b6040516100b29190610e3e565b60405180910390f35b6100d560048036038101906100d09190610db4565b6107c9565b6040516100e29190610e3e565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb8585856040518463ffffffff1660e01b815260040161015093929190610ee7565b6020604051808303816000875af115801561016f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101939190610f51565b9050806101d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101cc90610fca565b60405180910390fd5b600080fd5b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102629061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b81526004016102ac92919061107c565b602060405180830381865afa1580156102c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ed91906110ba565b101561032e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032590611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016103699190610bdd565b602060405180830381865afa158015610386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103aa91906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016103eb93929190611153565b6020604051808303816000875af115801561040a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042e9190610f51565b905080610470576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610467906111fc565b60405180910390fd5b848261047c919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016104b59190610bdd565b602060405180830381865afa1580156104d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f691906110ba565b14610536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052d906112cb565b60405180910390fd5b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3388886040518463ffffffff1660e01b815260040161057593929190610ee7565b6020604051808303816000875af1158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190610f51565b9050806105fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f190610fca565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016106339190610bdd565b602060405180830381865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067491906110ba565b91508273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33876040518363ffffffff1660e01b81526004016106b19291906112eb565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f49190610f51565b5084826107019190611314565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161073a9190610bdd565b602060405180830381865afa158015610757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077b91906110ba565b146107bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b290611394565b60405180910390fd5b600193505050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108519061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b815260040161089b92919061107c565b602060405180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc91906110ba565b101561091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091490611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109589190610bdd565b602060405180830381865afa158015610975573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099991906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016109da93929190611153565b6020604051808303816000875af11580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190610f51565b905080610a5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a56906111fc565b60405180910390fd5b8482610a6b919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610aa49190610bdd565b602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae591906110ba565b14610b25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1c906112cb565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16638f5184303388886040518463ffffffff1660e01b8152600401610b6293929190610ee7565b600060405180830381600087803b158015610b7c57600080fd5b505af1925050508015610b8d575060015b50600193505050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610bc782610b9c565b9050919050565b610bd781610bbc565b82525050565b6000602082019050610bf26000830184610bce565b92915050565b6000604051905090565b600080fd5b600080fd5b610c1581610bbc565b8114610c2057600080fd5b50565b600081359050610c3281610c0c565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610c8b82610c42565b810181811067ffffffffffffffff82111715610caa57610ca9610c53565b5b80604052505050565b6000610cbd610bf8565b9050610cc98282610c82565b919050565b600067ffffffffffffffff821115610ce957610ce8610c53565b5b610cf282610c42565b9050602081019050919050565b82818337600083830152505050565b6000610d21610d1c84610cce565b610cb3565b905082815260208101848484011115610d3d57610d3c610c3d565b5b610d48848285610cff565b509392505050565b600082601f830112610d6557610d64610c38565b5b8135610d75848260208601610d0e565b91505092915050565b6000819050919050565b610d9181610d7e565b8114610d9c57600080fd5b50565b600081359050610dae81610d88565b92915050565b600080600060608486031215610dcd57610dcc610c02565b5b6000610ddb86828701610c23565b935050602084013567ffffffffffffffff811115610dfc57610dfb610c07565b5b610e0886828701610d50565b9250506040610e1986828701610d9f565b9150509250925092565b60008115159050919050565b610e3881610e23565b82525050565b6000602082019050610e536000830184610e2f565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e93578082015181840152602081019050610e78565b60008484015250505050565b6000610eaa82610e59565b610eb48185610e64565b9350610ec4818560208601610e75565b610ecd81610c42565b840191505092915050565b610ee181610d7e565b82525050565b6000606082019050610efc6000830186610bce565b8181036020830152610f0e8185610e9f565b9050610f1d6040830184610ed8565b949350505050565b610f2e81610e23565b8114610f3957600080fd5b50565b600081519050610f4b81610f25565b92915050565b600060208284031215610f6757610f66610c02565b5b6000610f7584828501610f3c565b91505092915050565b7f6661696c656420746f2064656c65676174650000000000000000000000000000600082015250565b6000610fb4601283610e64565b9150610fbf82610f7e565b602082019050919050565b60006020820190508181036000830152610fe381610fa7565b9050919050565b7f4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f60008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b6000611046602183610e64565b915061105182610fea565b604082019050919050565b6000602082019050818103600083015261107581611039565b9050919050565b60006040820190506110916000830185610bce565b61109e6020830184610bce565b9392505050565b6000815190506110b481610d88565b92915050565b6000602082840312156110d0576110cf610c02565b5b60006110de848285016110a5565b91505092915050565b7f496e73756666696369656e7420616c6c6f77616e636500000000000000000000600082015250565b600061111d601683610e64565b9150611128826110e7565b602082019050919050565b6000602082019050818103600083015261114c81611110565b9050919050565b60006060820190506111686000830186610bce565b6111756020830185610bce565b6111826040830184610ed8565b949350505050565b7f4661696c656420746f207472616e7366657220746f6b656e7320666f7220666c60008201527f617368206c6f616e000000000000000000000000000000000000000000000000602082015250565b60006111e6602883610e64565b91506111f18261118a565b604082019050919050565b60006020820190508181036000830152611215816111d9565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061125682610d7e565b915061126183610d7e565b92508282019050808211156112795761127861121c565b5b92915050565b7f466c617368206c6f616e206661696c6564000000000000000000000000000000600082015250565b60006112b5601183610e64565b91506112c08261127f565b602082019050919050565b600060208201905081810360008301526112e4816112a8565b9050919050565b60006040820190506113006000830185610bce565b61130d6020830184610ed8565b9392505050565b600061131f82610d7e565b915061132a83610d7e565b92508282039050818111156113425761134161121c565b5b92915050565b7f466c617368206c6f616e2072657061796d656e74206661696c65640000000000600082015250565b600061137e601b83610e64565b915061138982611348565b602082019050919050565b600060208201905081810360008301526113ad81611371565b905091905056fea2646970667358221220c424c19551d9b4559d960ffe973aece9d88bd266c540f629abf8f11eb26a6c1e64736f6c63430008120033", + "bytecode": "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506113ea806100606000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80638da5cb5b146100515780638f5184301461006f578063ee52ad711461008b578063f12fae93146100bb575b600080fd5b6100596100eb565b6040516100669190610bdd565b60405180910390f35b61008960048036038101906100849190610db4565b61010f565b005b6100a560048036038101906100a09190610db4565b6101da565b6040516100b29190610e3e565b60405180910390f35b6100d560048036038101906100d09190610db4565b6107c9565b6040516100e29190610e3e565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb8585856040518463ffffffff1660e01b815260040161015093929190610ee7565b6020604051808303816000875af115801561016f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101939190610f51565b9050806101d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101cc90610fca565b60405180910390fd5b600080fd5b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102629061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b81526004016102ac92919061107c565b602060405180830381865afa1580156102c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ed91906110ba565b101561032e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032590611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016103699190610bdd565b602060405180830381865afa158015610386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103aa91906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016103eb93929190611153565b6020604051808303816000875af115801561040a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042e9190610f51565b905080610470576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610467906111fc565b60405180910390fd5b848261047c919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016104b59190610bdd565b602060405180830381865afa1580156104d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f691906110ba565b14610536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052d906112cb565b60405180910390fd5b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3388886040518463ffffffff1660e01b815260040161057593929190610ee7565b6020604051808303816000875af1158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190610f51565b9050806105fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f190610fca565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016106339190610bdd565b602060405180830381865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067491906110ba565b91508273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33876040518363ffffffff1660e01b81526004016106b19291906112eb565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f49190610f51565b5084826107019190611314565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161073a9190610bdd565b602060405180830381865afa158015610757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077b91906110ba565b146107bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b290611394565b60405180910390fd5b600193505050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108519061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b815260040161089b92919061107c565b602060405180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc91906110ba565b101561091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091490611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109589190610bdd565b602060405180830381865afa158015610975573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099991906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016109da93929190611153565b6020604051808303816000875af11580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190610f51565b905080610a5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a56906111fc565b60405180910390fd5b8482610a6b919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610aa49190610bdd565b602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae591906110ba565b14610b25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1c906112cb565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16638f5184303388886040518463ffffffff1660e01b8152600401610b6293929190610ee7565b600060405180830381600087803b158015610b7c57600080fd5b505af1925050508015610b8d575060015b50600193505050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610bc782610b9c565b9050919050565b610bd781610bbc565b82525050565b6000602082019050610bf26000830184610bce565b92915050565b6000604051905090565b600080fd5b600080fd5b610c1581610bbc565b8114610c2057600080fd5b50565b600081359050610c3281610c0c565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610c8b82610c42565b810181811067ffffffffffffffff82111715610caa57610ca9610c53565b5b80604052505050565b6000610cbd610bf8565b9050610cc98282610c82565b919050565b600067ffffffffffffffff821115610ce957610ce8610c53565b5b610cf282610c42565b9050602081019050919050565b82818337600083830152505050565b6000610d21610d1c84610cce565b610cb3565b905082815260208101848484011115610d3d57610d3c610c3d565b5b610d48848285610cff565b509392505050565b600082601f830112610d6557610d64610c38565b5b8135610d75848260208601610d0e565b91505092915050565b6000819050919050565b610d9181610d7e565b8114610d9c57600080fd5b50565b600081359050610dae81610d88565b92915050565b600080600060608486031215610dcd57610dcc610c02565b5b6000610ddb86828701610c23565b935050602084013567ffffffffffffffff811115610dfc57610dfb610c07565b5b610e0886828701610d50565b9250506040610e1986828701610d9f565b9150509250925092565b60008115159050919050565b610e3881610e23565b82525050565b6000602082019050610e536000830184610e2f565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e93578082015181840152602081019050610e78565b60008484015250505050565b6000610eaa82610e59565b610eb48185610e64565b9350610ec4818560208601610e75565b610ecd81610c42565b840191505092915050565b610ee181610d7e565b82525050565b6000606082019050610efc6000830186610bce565b8181036020830152610f0e8185610e9f565b9050610f1d6040830184610ed8565b949350505050565b610f2e81610e23565b8114610f3957600080fd5b50565b600081519050610f4b81610f25565b92915050565b600060208284031215610f6757610f66610c02565b5b6000610f7584828501610f3c565b91505092915050565b7f6661696c656420746f2064656c65676174650000000000000000000000000000600082015250565b6000610fb4601283610e64565b9150610fbf82610f7e565b602082019050919050565b60006020820190508181036000830152610fe381610fa7565b9050919050565b7f4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f60008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b6000611046602183610e64565b915061105182610fea565b604082019050919050565b6000602082019050818103600083015261107581611039565b9050919050565b60006040820190506110916000830185610bce565b61109e6020830184610bce565b9392505050565b6000815190506110b481610d88565b92915050565b6000602082840312156110d0576110cf610c02565b5b60006110de848285016110a5565b91505092915050565b7f496e73756666696369656e7420616c6c6f77616e636500000000000000000000600082015250565b600061111d601683610e64565b9150611128826110e7565b602082019050919050565b6000602082019050818103600083015261114c81611110565b9050919050565b60006060820190506111686000830186610bce565b6111756020830185610bce565b6111826040830184610ed8565b949350505050565b7f4661696c656420746f207472616e7366657220746f6b656e7320666f7220666c60008201527f617368206c6f616e000000000000000000000000000000000000000000000000602082015250565b60006111e6602883610e64565b91506111f18261118a565b604082019050919050565b60006020820190508181036000830152611215816111d9565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061125682610d7e565b915061126183610d7e565b92508282019050808211156112795761127861121c565b5b92915050565b7f466c617368206c6f616e206661696c6564000000000000000000000000000000600082015250565b60006112b5601183610e64565b91506112c08261127f565b602082019050919050565b600060208201905081810360008301526112e4816112a8565b9050919050565b60006040820190506113006000830185610bce565b61130d6020830184610ed8565b9392505050565b600061131f82610d7e565b915061132a83610d7e565b92508282039050818111156113425761134161121c565b5b92915050565b7f466c617368206c6f616e2072657061796d656e74206661696c65640000000000600082015250565b600061137e601b83610e64565b915061138982611348565b602082019050919050565b600060208201905081810360008301526113ad81611371565b905091905056fea26469706673582212208e1d52c36a32622af075b98cf15a237fb7323d1e2ace6e9cb8d762d107b21e9864736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80638da5cb5b146100515780638f5184301461006f578063ee52ad711461008b578063f12fae93146100bb575b600080fd5b6100596100eb565b6040516100669190610bdd565b60405180910390f35b61008960048036038101906100849190610db4565b61010f565b005b6100a560048036038101906100a09190610db4565b6101da565b6040516100b29190610e3e565b60405180910390f35b6100d560048036038101906100d09190610db4565b6107c9565b6040516100e29190610e3e565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb8585856040518463ffffffff1660e01b815260040161015093929190610ee7565b6020604051808303816000875af115801561016f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101939190610f51565b9050806101d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101cc90610fca565b60405180910390fd5b600080fd5b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102629061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b81526004016102ac92919061107c565b602060405180830381865afa1580156102c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ed91906110ba565b101561032e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032590611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016103699190610bdd565b602060405180830381865afa158015610386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103aa91906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016103eb93929190611153565b6020604051808303816000875af115801561040a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042e9190610f51565b905080610470576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610467906111fc565b60405180910390fd5b848261047c919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016104b59190610bdd565b602060405180830381865afa1580156104d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f691906110ba565b14610536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052d906112cb565b60405180910390fd5b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3388886040518463ffffffff1660e01b815260040161057593929190610ee7565b6020604051808303816000875af1158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190610f51565b9050806105fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f190610fca565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016106339190610bdd565b602060405180830381865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067491906110ba565b91508273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33876040518363ffffffff1660e01b81526004016106b19291906112eb565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f49190610f51565b5084826107019190611314565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161073a9190610bdd565b602060405180830381865afa158015610757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077b91906110ba565b146107bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b290611394565b60405180910390fd5b600193505050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108519061105c565b60405180910390fd5b6000849050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b815260040161089b92919061107c565b602060405180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc91906110ba565b101561091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091490611133565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109589190610bdd565b602060405180830381865afa158015610975573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099991906110ba565b905060008273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b81526004016109da93929190611153565b6020604051808303816000875af11580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190610f51565b905080610a5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a56906111fc565b60405180910390fd5b8482610a6b919061124b565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610aa49190610bdd565b602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae591906110ba565b14610b25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1c906112cb565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16638f5184303388886040518463ffffffff1660e01b8152600401610b6293929190610ee7565b600060405180830381600087803b158015610b7c57600080fd5b505af1925050508015610b8d575060015b50600193505050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610bc782610b9c565b9050919050565b610bd781610bbc565b82525050565b6000602082019050610bf26000830184610bce565b92915050565b6000604051905090565b600080fd5b600080fd5b610c1581610bbc565b8114610c2057600080fd5b50565b600081359050610c3281610c0c565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610c8b82610c42565b810181811067ffffffffffffffff82111715610caa57610ca9610c53565b5b80604052505050565b6000610cbd610bf8565b9050610cc98282610c82565b919050565b600067ffffffffffffffff821115610ce957610ce8610c53565b5b610cf282610c42565b9050602081019050919050565b82818337600083830152505050565b6000610d21610d1c84610cce565b610cb3565b905082815260208101848484011115610d3d57610d3c610c3d565b5b610d48848285610cff565b509392505050565b600082601f830112610d6557610d64610c38565b5b8135610d75848260208601610d0e565b91505092915050565b6000819050919050565b610d9181610d7e565b8114610d9c57600080fd5b50565b600081359050610dae81610d88565b92915050565b600080600060608486031215610dcd57610dcc610c02565b5b6000610ddb86828701610c23565b935050602084013567ffffffffffffffff811115610dfc57610dfb610c07565b5b610e0886828701610d50565b9250506040610e1986828701610d9f565b9150509250925092565b60008115159050919050565b610e3881610e23565b82525050565b6000602082019050610e536000830184610e2f565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e93578082015181840152602081019050610e78565b60008484015250505050565b6000610eaa82610e59565b610eb48185610e64565b9350610ec4818560208601610e75565b610ecd81610c42565b840191505092915050565b610ee181610d7e565b82525050565b6000606082019050610efc6000830186610bce565b8181036020830152610f0e8185610e9f565b9050610f1d6040830184610ed8565b949350505050565b610f2e81610e23565b8114610f3957600080fd5b50565b600081519050610f4b81610f25565b92915050565b600060208284031215610f6757610f66610c02565b5b6000610f7584828501610f3c565b91505092915050565b7f6661696c656420746f2064656c65676174650000000000000000000000000000600082015250565b6000610fb4601283610e64565b9150610fbf82610f7e565b602082019050919050565b60006020820190508181036000830152610fe381610fa7565b9050919050565b7f4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f60008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b6000611046602183610e64565b915061105182610fea565b604082019050919050565b6000602082019050818103600083015261107581611039565b9050919050565b60006040820190506110916000830185610bce565b61109e6020830184610bce565b9392505050565b6000815190506110b481610d88565b92915050565b6000602082840312156110d0576110cf610c02565b5b60006110de848285016110a5565b91505092915050565b7f496e73756666696369656e7420616c6c6f77616e636500000000000000000000600082015250565b600061111d601683610e64565b9150611128826110e7565b602082019050919050565b6000602082019050818103600083015261114c81611110565b9050919050565b60006060820190506111686000830186610bce565b6111756020830185610bce565b6111826040830184610ed8565b949350505050565b7f4661696c656420746f207472616e7366657220746f6b656e7320666f7220666c60008201527f617368206c6f616e000000000000000000000000000000000000000000000000602082015250565b60006111e6602883610e64565b91506111f18261118a565b604082019050919050565b60006020820190508181036000830152611215816111d9565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061125682610d7e565b915061126183610d7e565b92508282019050808211156112795761127861121c565b5b92915050565b7f466c617368206c6f616e206661696c6564000000000000000000000000000000600082015250565b60006112b5601183610e64565b91506112c08261127f565b602082019050919050565b600060208201905081810360008301526112e4816112a8565b9050919050565b60006040820190506113006000830185610bce565b61130d6020830184610ed8565b9392505050565b600061131f82610d7e565b915061132a83610d7e565b92508282039050818111156113425761134161121c565b5b92915050565b7f466c617368206c6f616e2072657061796d656e74206661696c65640000000000600082015250565b600061137e601b83610e64565b915061138982611348565b602082019050919050565b600060208201905081810360008301526113ad81611371565b905091905056fea26469706673582212208e1d52c36a32622af075b98cf15a237fb7323d1e2ace6e9cb8d762d107b21e9864736f6c63430008130033", "linkReferences": {}, "deployedLinkReferences": {} }
precompiles/testutil/contracts/FlashLoan.sol+3 −3 modified@@ -28,7 +28,7 @@ contract FlashLoan { uint256 balancePre = token.balanceOf(address(this)); bool success = token.transferFrom(msg.sender, address(this), _amount); require(success, "Failed to transfer tokens for flash loan"); - assert( + require( token.balanceOf(address(this)) == balancePre + _amount, "Flash loan failed" ); @@ -44,7 +44,7 @@ contract FlashLoan { // Transfer tokens back to end the flash loan balancePre = token.balanceOf(address(this)); token.transfer(msg.sender, _amount); - assert( + require( token.balanceOf(address(this)) == balancePre - _amount, "Flash loan repayment failed" ); @@ -69,7 +69,7 @@ contract FlashLoan { uint256 balancePre = token.balanceOf(address(this)); bool success = token.transferFrom(msg.sender, address(this), _amount); require(success, "Failed to transfer tokens for flash loan"); - assert( + require( token.balanceOf(address(this)) == balancePre + _amount, "Flash loan failed" );
precompiles/testutil/contracts/ICounter.sol+9 −0 added@@ -0,0 +1,9 @@ +pragma solidity ^0.8.17; + +interface ICounter { + function add() external; + function subtract() external; + function getCounter() external view returns (uint256); + event Changed(uint256 counter); + event Added(uint256 counter); +}
precompiles/testutil/contracts/Reverter.json+2 −2 modified@@ -38,8 +38,8 @@ "type": "receive" } ], - "bytecode": "0x608060405260008055610c17806100176000396000f3fe60806040526004361061002d5760003560e01c806379388e9414610039578063c04062261461006257610034565b3661003457005b600080fd5b34801561004557600080fd5b50610060600480360381019061005b9190610360565b610079565b005b34801561006e57600080fd5b50610077610131565b005b808290604051610088906102d4565b82906040518091039083f590509050801580156100a9573d6000803e3d6000fd5b505061080173ffffffffffffffffffffffffffffffffffffffff166354be1a28306040518263ffffffff1660e01b81526004016100e691906103e1565b600060405180830381865afa158015610103573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061012c9190610884565b600080fd5b6000808154809291906101439061092b565b91905055503073ffffffffffffffffffffffffffffffffffffffff166379388e9460005460001b476040518363ffffffff1660e01b8152600401610188929190610991565b600060405180830381600087803b1580156101a257600080fd5b505af19250505080156101b3575060015b61022f5760006101c760005460001b610249565b90508073ffffffffffffffffffffffffffffffffffffffff16633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561021157600080fd5b505af1158015610225573d6000803e3d6000fd5b5050505050610230565b5b6000808154809291906102429061092b565b9190505550565b60008060ff60f81b308460405180602001610263906102d4565b6020820181038252601f19601f820116604052506040516020016102879190610a01565b604051602081830303815290604052805190602001206040516020016102b09493929190610ace565b6040516020818303038152906040528051906020012060001c905080915050919050565b60c580610b1d83390190565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b610307816102f4565b811461031257600080fd5b50565b600081359050610324816102fe565b92915050565b6000819050919050565b61033d8161032a565b811461034857600080fd5b50565b60008135905061035a81610334565b92915050565b60008060408385031215610377576103766102ea565b5b600061038585828601610315565b92505060206103968582860161034b565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103cb826103a0565b9050919050565b6103db816103c0565b82525050565b60006020820190506103f660008301846103d2565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61044a82610401565b810181811067ffffffffffffffff8211171561046957610468610412565b5b80604052505050565b600061047c6102e0565b90506104888282610441565b919050565b600067ffffffffffffffff8211156104a8576104a7610412565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff8211156104e8576104e7610412565b5b6104f182610401565b9050602081019050919050565b60005b8381101561051c578082015181840152602081019050610501565b60008484015250505050565b600061053b610536846104cd565b610472565b905082815260208101848484011115610557576105566104c8565b5b6105628482856104fe565b509392505050565b600082601f83011261057f5761057e6103fc565b5b815161058f848260208601610528565b91505092915050565b600067ffffffffffffffff8211156105b3576105b2610412565b5b602082029050602081019050919050565b6000815190506105d381610334565b92915050565b600060ff82169050919050565b6105ef816105d9565b81146105fa57600080fd5b50565b60008151905061060c816105e6565b92915050565b600060608284031215610628576106276104be565b5b6106326060610472565b9050600082015167ffffffffffffffff811115610652576106516104c3565b5b61065e8482850161056a565b6000830152506020610672848285016105c4565b6020830152506040610686848285016105fd565b60408301525092915050565b60006106a56106a084610598565b610472565b905080838252602082019050602084028301858111156106c8576106c76104b9565b5b835b8181101561070f57805167ffffffffffffffff8111156106ed576106ec6103fc565b5b8086016106fa8982610612565b855260208501945050506020810190506106ca565b5050509392505050565b600082601f83011261072e5761072d6103fc565b5b815161073e848260208601610692565b91505092915050565b60006040828403121561075d5761075c6104be565b5b6107676040610472565b9050600082015167ffffffffffffffff811115610787576107866104c3565b5b6107938482850161056a565b600083015250602082015167ffffffffffffffff8111156107b7576107b66104c3565b5b6107c384828501610719565b60208301525092915050565b60006107e26107dd8461048d565b610472565b90508083825260208201905060208402830185811115610805576108046104b9565b5b835b8181101561084c57805167ffffffffffffffff81111561082a576108296103fc565b5b8086016108378982610747565b85526020850194505050602081019050610807565b5050509392505050565b600082601f83011261086b5761086a6103fc565b5b815161087b8482602086016107cf565b91505092915050565b6000806040838503121561089b5761089a6102ea565b5b600083015167ffffffffffffffff8111156108b9576108b86102ef565b5b6108c585828601610856565b925050602083015167ffffffffffffffff8111156108e6576108e56102ef565b5b6108f285828601610719565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006109368261032a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610968576109676108fc565b5b600182019050919050565b61097c816102f4565b82525050565b61098b8161032a565b82525050565b60006040820190506109a66000830185610973565b6109b36020830184610982565b9392505050565b600081519050919050565b600081905092915050565b60006109db826109ba565b6109e581856109c5565b93506109f58185602086016104fe565b80840191505092915050565b6000610a0d82846109d0565b915081905092915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610a5f610a5a82610a18565b610a44565b82525050565b60008160601b9050919050565b6000610a7d82610a65565b9050919050565b6000610a8f82610a72565b9050919050565b610aa7610aa2826103c0565b610a84565b82525050565b6000819050919050565b610ac8610ac3826102f4565b610aad565b82525050565b6000610ada8287610a4e565b600182019150610aea8286610a96565b601482019150610afa8285610ab7565b602082019150610b0a8284610ab7565b6020820191508190509594505050505056fe608060405260b3806100126000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633ccfd60b14602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015607a573d6000803e3d6000fd5b5056fea264697066735822122008001b1cb780fb8c81d5ab538ccbeab143f74b68ef571f3c5d058a2620bf412864736f6c63430008130033a2646970667358221220a5fd3d44b59916cad19784e497c1dbfaa58f7fb8006170e93ea2c8bd32af7b0264736f6c63430008130033", - "deployedBytecode": "0x60806040526004361061002d5760003560e01c806379388e9414610039578063c04062261461006257610034565b3661003457005b600080fd5b34801561004557600080fd5b50610060600480360381019061005b9190610360565b610079565b005b34801561006e57600080fd5b50610077610131565b005b808290604051610088906102d4565b82906040518091039083f590509050801580156100a9573d6000803e3d6000fd5b505061080173ffffffffffffffffffffffffffffffffffffffff166354be1a28306040518263ffffffff1660e01b81526004016100e691906103e1565b600060405180830381865afa158015610103573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061012c9190610884565b600080fd5b6000808154809291906101439061092b565b91905055503073ffffffffffffffffffffffffffffffffffffffff166379388e9460005460001b476040518363ffffffff1660e01b8152600401610188929190610991565b600060405180830381600087803b1580156101a257600080fd5b505af19250505080156101b3575060015b61022f5760006101c760005460001b610249565b90508073ffffffffffffffffffffffffffffffffffffffff16633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561021157600080fd5b505af1158015610225573d6000803e3d6000fd5b5050505050610230565b5b6000808154809291906102429061092b565b9190505550565b60008060ff60f81b308460405180602001610263906102d4565b6020820181038252601f19601f820116604052506040516020016102879190610a01565b604051602081830303815290604052805190602001206040516020016102b09493929190610ace565b6040516020818303038152906040528051906020012060001c905080915050919050565b60c580610b1d83390190565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b610307816102f4565b811461031257600080fd5b50565b600081359050610324816102fe565b92915050565b6000819050919050565b61033d8161032a565b811461034857600080fd5b50565b60008135905061035a81610334565b92915050565b60008060408385031215610377576103766102ea565b5b600061038585828601610315565b92505060206103968582860161034b565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103cb826103a0565b9050919050565b6103db816103c0565b82525050565b60006020820190506103f660008301846103d2565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61044a82610401565b810181811067ffffffffffffffff8211171561046957610468610412565b5b80604052505050565b600061047c6102e0565b90506104888282610441565b919050565b600067ffffffffffffffff8211156104a8576104a7610412565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff8211156104e8576104e7610412565b5b6104f182610401565b9050602081019050919050565b60005b8381101561051c578082015181840152602081019050610501565b60008484015250505050565b600061053b610536846104cd565b610472565b905082815260208101848484011115610557576105566104c8565b5b6105628482856104fe565b509392505050565b600082601f83011261057f5761057e6103fc565b5b815161058f848260208601610528565b91505092915050565b600067ffffffffffffffff8211156105b3576105b2610412565b5b602082029050602081019050919050565b6000815190506105d381610334565b92915050565b600060ff82169050919050565b6105ef816105d9565b81146105fa57600080fd5b50565b60008151905061060c816105e6565b92915050565b600060608284031215610628576106276104be565b5b6106326060610472565b9050600082015167ffffffffffffffff811115610652576106516104c3565b5b61065e8482850161056a565b6000830152506020610672848285016105c4565b6020830152506040610686848285016105fd565b60408301525092915050565b60006106a56106a084610598565b610472565b905080838252602082019050602084028301858111156106c8576106c76104b9565b5b835b8181101561070f57805167ffffffffffffffff8111156106ed576106ec6103fc565b5b8086016106fa8982610612565b855260208501945050506020810190506106ca565b5050509392505050565b600082601f83011261072e5761072d6103fc565b5b815161073e848260208601610692565b91505092915050565b60006040828403121561075d5761075c6104be565b5b6107676040610472565b9050600082015167ffffffffffffffff811115610787576107866104c3565b5b6107938482850161056a565b600083015250602082015167ffffffffffffffff8111156107b7576107b66104c3565b5b6107c384828501610719565b60208301525092915050565b60006107e26107dd8461048d565b610472565b90508083825260208201905060208402830185811115610805576108046104b9565b5b835b8181101561084c57805167ffffffffffffffff81111561082a576108296103fc565b5b8086016108378982610747565b85526020850194505050602081019050610807565b5050509392505050565b600082601f83011261086b5761086a6103fc565b5b815161087b8482602086016107cf565b91505092915050565b6000806040838503121561089b5761089a6102ea565b5b600083015167ffffffffffffffff8111156108b9576108b86102ef565b5b6108c585828601610856565b925050602083015167ffffffffffffffff8111156108e6576108e56102ef565b5b6108f285828601610719565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006109368261032a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610968576109676108fc565b5b600182019050919050565b61097c816102f4565b82525050565b61098b8161032a565b82525050565b60006040820190506109a66000830185610973565b6109b36020830184610982565b9392505050565b600081519050919050565b600081905092915050565b60006109db826109ba565b6109e581856109c5565b93506109f58185602086016104fe565b80840191505092915050565b6000610a0d82846109d0565b915081905092915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610a5f610a5a82610a18565b610a44565b82525050565b60008160601b9050919050565b6000610a7d82610a65565b9050919050565b6000610a8f82610a72565b9050919050565b610aa7610aa2826103c0565b610a84565b82525050565b6000819050919050565b610ac8610ac3826102f4565b610aad565b82525050565b6000610ada8287610a4e565b600182019150610aea8286610a96565b601482019150610afa8285610ab7565b602082019150610b0a8284610ab7565b6020820191508190509594505050505056fe608060405260b3806100126000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633ccfd60b14602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015607a573d6000803e3d6000fd5b5056fea264697066735822122008001b1cb780fb8c81d5ab538ccbeab143f74b68ef571f3c5d058a2620bf412864736f6c63430008130033a2646970667358221220a5fd3d44b59916cad19784e497c1dbfaa58f7fb8006170e93ea2c8bd32af7b0264736f6c63430008130033", + "bytecode": "0x608060405260008055610c17806100176000396000f3fe60806040526004361061002d5760003560e01c806379388e9414610039578063c04062261461006257610034565b3661003457005b600080fd5b34801561004557600080fd5b50610060600480360381019061005b9190610360565b610079565b005b34801561006e57600080fd5b50610077610131565b005b808290604051610088906102d4565b82906040518091039083f590509050801580156100a9573d6000803e3d6000fd5b505061080173ffffffffffffffffffffffffffffffffffffffff166354be1a28306040518263ffffffff1660e01b81526004016100e691906103e1565b600060405180830381865afa158015610103573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061012c9190610884565b600080fd5b6000808154809291906101439061092b565b91905055503073ffffffffffffffffffffffffffffffffffffffff166379388e9460005460001b476040518363ffffffff1660e01b8152600401610188929190610991565b600060405180830381600087803b1580156101a257600080fd5b505af19250505080156101b3575060015b61022f5760006101c760005460001b610249565b90508073ffffffffffffffffffffffffffffffffffffffff16633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561021157600080fd5b505af1158015610225573d6000803e3d6000fd5b5050505050610230565b5b6000808154809291906102429061092b565b9190505550565b60008060ff60f81b308460405180602001610263906102d4565b6020820181038252601f19601f820116604052506040516020016102879190610a01565b604051602081830303815290604052805190602001206040516020016102b09493929190610ace565b6040516020818303038152906040528051906020012060001c905080915050919050565b60c580610b1d83390190565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b610307816102f4565b811461031257600080fd5b50565b600081359050610324816102fe565b92915050565b6000819050919050565b61033d8161032a565b811461034857600080fd5b50565b60008135905061035a81610334565b92915050565b60008060408385031215610377576103766102ea565b5b600061038585828601610315565b92505060206103968582860161034b565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103cb826103a0565b9050919050565b6103db816103c0565b82525050565b60006020820190506103f660008301846103d2565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61044a82610401565b810181811067ffffffffffffffff8211171561046957610468610412565b5b80604052505050565b600061047c6102e0565b90506104888282610441565b919050565b600067ffffffffffffffff8211156104a8576104a7610412565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff8211156104e8576104e7610412565b5b6104f182610401565b9050602081019050919050565b60005b8381101561051c578082015181840152602081019050610501565b60008484015250505050565b600061053b610536846104cd565b610472565b905082815260208101848484011115610557576105566104c8565b5b6105628482856104fe565b509392505050565b600082601f83011261057f5761057e6103fc565b5b815161058f848260208601610528565b91505092915050565b600067ffffffffffffffff8211156105b3576105b2610412565b5b602082029050602081019050919050565b6000815190506105d381610334565b92915050565b600060ff82169050919050565b6105ef816105d9565b81146105fa57600080fd5b50565b60008151905061060c816105e6565b92915050565b600060608284031215610628576106276104be565b5b6106326060610472565b9050600082015167ffffffffffffffff811115610652576106516104c3565b5b61065e8482850161056a565b6000830152506020610672848285016105c4565b6020830152506040610686848285016105fd565b60408301525092915050565b60006106a56106a084610598565b610472565b905080838252602082019050602084028301858111156106c8576106c76104b9565b5b835b8181101561070f57805167ffffffffffffffff8111156106ed576106ec6103fc565b5b8086016106fa8982610612565b855260208501945050506020810190506106ca565b5050509392505050565b600082601f83011261072e5761072d6103fc565b5b815161073e848260208601610692565b91505092915050565b60006040828403121561075d5761075c6104be565b5b6107676040610472565b9050600082015167ffffffffffffffff811115610787576107866104c3565b5b6107938482850161056a565b600083015250602082015167ffffffffffffffff8111156107b7576107b66104c3565b5b6107c384828501610719565b60208301525092915050565b60006107e26107dd8461048d565b610472565b90508083825260208201905060208402830185811115610805576108046104b9565b5b835b8181101561084c57805167ffffffffffffffff81111561082a576108296103fc565b5b8086016108378982610747565b85526020850194505050602081019050610807565b5050509392505050565b600082601f83011261086b5761086a6103fc565b5b815161087b8482602086016107cf565b91505092915050565b6000806040838503121561089b5761089a6102ea565b5b600083015167ffffffffffffffff8111156108b9576108b86102ef565b5b6108c585828601610856565b925050602083015167ffffffffffffffff8111156108e6576108e56102ef565b5b6108f285828601610719565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006109368261032a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610968576109676108fc565b5b600182019050919050565b61097c816102f4565b82525050565b61098b8161032a565b82525050565b60006040820190506109a66000830185610973565b6109b36020830184610982565b9392505050565b600081519050919050565b600081905092915050565b60006109db826109ba565b6109e581856109c5565b93506109f58185602086016104fe565b80840191505092915050565b6000610a0d82846109d0565b915081905092915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610a5f610a5a82610a18565b610a44565b82525050565b60008160601b9050919050565b6000610a7d82610a65565b9050919050565b6000610a8f82610a72565b9050919050565b610aa7610aa2826103c0565b610a84565b82525050565b6000819050919050565b610ac8610ac3826102f4565b610aad565b82525050565b6000610ada8287610a4e565b600182019150610aea8286610a96565b601482019150610afa8285610ab7565b602082019150610b0a8284610ab7565b6020820191508190509594505050505056fe608060405260b3806100126000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633ccfd60b14602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015607a573d6000803e3d6000fd5b5056fea26469706673582212200cca7e94767cc41a8eff494693f692a362784efcf8724ef105e5c5948d07a98a64736f6c63430008130033a26469706673582212209eedc0bf8ca98ddf4547c45c1938b3294a8c876293b916e6991af709591c556764736f6c63430008130033", + "deployedBytecode": "0x60806040526004361061002d5760003560e01c806379388e9414610039578063c04062261461006257610034565b3661003457005b600080fd5b34801561004557600080fd5b50610060600480360381019061005b9190610360565b610079565b005b34801561006e57600080fd5b50610077610131565b005b808290604051610088906102d4565b82906040518091039083f590509050801580156100a9573d6000803e3d6000fd5b505061080173ffffffffffffffffffffffffffffffffffffffff166354be1a28306040518263ffffffff1660e01b81526004016100e691906103e1565b600060405180830381865afa158015610103573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061012c9190610884565b600080fd5b6000808154809291906101439061092b565b91905055503073ffffffffffffffffffffffffffffffffffffffff166379388e9460005460001b476040518363ffffffff1660e01b8152600401610188929190610991565b600060405180830381600087803b1580156101a257600080fd5b505af19250505080156101b3575060015b61022f5760006101c760005460001b610249565b90508073ffffffffffffffffffffffffffffffffffffffff16633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561021157600080fd5b505af1158015610225573d6000803e3d6000fd5b5050505050610230565b5b6000808154809291906102429061092b565b9190505550565b60008060ff60f81b308460405180602001610263906102d4565b6020820181038252601f19601f820116604052506040516020016102879190610a01565b604051602081830303815290604052805190602001206040516020016102b09493929190610ace565b6040516020818303038152906040528051906020012060001c905080915050919050565b60c580610b1d83390190565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b610307816102f4565b811461031257600080fd5b50565b600081359050610324816102fe565b92915050565b6000819050919050565b61033d8161032a565b811461034857600080fd5b50565b60008135905061035a81610334565b92915050565b60008060408385031215610377576103766102ea565b5b600061038585828601610315565b92505060206103968582860161034b565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103cb826103a0565b9050919050565b6103db816103c0565b82525050565b60006020820190506103f660008301846103d2565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61044a82610401565b810181811067ffffffffffffffff8211171561046957610468610412565b5b80604052505050565b600061047c6102e0565b90506104888282610441565b919050565b600067ffffffffffffffff8211156104a8576104a7610412565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff8211156104e8576104e7610412565b5b6104f182610401565b9050602081019050919050565b60005b8381101561051c578082015181840152602081019050610501565b60008484015250505050565b600061053b610536846104cd565b610472565b905082815260208101848484011115610557576105566104c8565b5b6105628482856104fe565b509392505050565b600082601f83011261057f5761057e6103fc565b5b815161058f848260208601610528565b91505092915050565b600067ffffffffffffffff8211156105b3576105b2610412565b5b602082029050602081019050919050565b6000815190506105d381610334565b92915050565b600060ff82169050919050565b6105ef816105d9565b81146105fa57600080fd5b50565b60008151905061060c816105e6565b92915050565b600060608284031215610628576106276104be565b5b6106326060610472565b9050600082015167ffffffffffffffff811115610652576106516104c3565b5b61065e8482850161056a565b6000830152506020610672848285016105c4565b6020830152506040610686848285016105fd565b60408301525092915050565b60006106a56106a084610598565b610472565b905080838252602082019050602084028301858111156106c8576106c76104b9565b5b835b8181101561070f57805167ffffffffffffffff8111156106ed576106ec6103fc565b5b8086016106fa8982610612565b855260208501945050506020810190506106ca565b5050509392505050565b600082601f83011261072e5761072d6103fc565b5b815161073e848260208601610692565b91505092915050565b60006040828403121561075d5761075c6104be565b5b6107676040610472565b9050600082015167ffffffffffffffff811115610787576107866104c3565b5b6107938482850161056a565b600083015250602082015167ffffffffffffffff8111156107b7576107b66104c3565b5b6107c384828501610719565b60208301525092915050565b60006107e26107dd8461048d565b610472565b90508083825260208201905060208402830185811115610805576108046104b9565b5b835b8181101561084c57805167ffffffffffffffff81111561082a576108296103fc565b5b8086016108378982610747565b85526020850194505050602081019050610807565b5050509392505050565b600082601f83011261086b5761086a6103fc565b5b815161087b8482602086016107cf565b91505092915050565b6000806040838503121561089b5761089a6102ea565b5b600083015167ffffffffffffffff8111156108b9576108b86102ef565b5b6108c585828601610856565b925050602083015167ffffffffffffffff8111156108e6576108e56102ef565b5b6108f285828601610719565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006109368261032a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610968576109676108fc565b5b600182019050919050565b61097c816102f4565b82525050565b61098b8161032a565b82525050565b60006040820190506109a66000830185610973565b6109b36020830184610982565b9392505050565b600081519050919050565b600081905092915050565b60006109db826109ba565b6109e581856109c5565b93506109f58185602086016104fe565b80840191505092915050565b6000610a0d82846109d0565b915081905092915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610a5f610a5a82610a18565b610a44565b82525050565b60008160601b9050919050565b6000610a7d82610a65565b9050919050565b6000610a8f82610a72565b9050919050565b610aa7610aa2826103c0565b610a84565b82525050565b6000819050919050565b610ac8610ac3826102f4565b610aad565b82525050565b6000610ada8287610a4e565b600182019150610aea8286610a96565b601482019150610afa8285610ab7565b602082019150610b0a8284610ab7565b6020820191508190509594505050505056fe608060405260b3806100126000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633ccfd60b14602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015607a573d6000803e3d6000fd5b5056fea26469706673582212200cca7e94767cc41a8eff494693f692a362784efcf8724ef105e5c5948d07a98a64736f6c63430008130033a26469706673582212209eedc0bf8ca98ddf4547c45c1938b3294a8c876293b916e6991af709591c556764736f6c63430008130033", "linkReferences": {}, "deployedLinkReferences": {} }
precompiles/vesting/errors.go+2 −0 modified@@ -7,4 +7,6 @@ const ( ErrDifferentFromOrigin = "tx origin address %s does not match the from address %s" // ErrDifferentFunderOrigin is raised when the tx origin address is not the same as the vesting transaction funder. ErrDifferentFunderOrigin = "tx origin address %s does not match the funder address %s" + // ErrInvalidDestination is raised when the destination address is not an EOA or the contract calling the precompile. + ErrInvalidDestination = "invalid destination address %s. Should be an EOA or the contract calling the precompile" )
precompiles/vesting/events.go+0 −4 modified@@ -90,10 +90,6 @@ func (p Precompile) EmitCreateClawbackVestingAccountEvent( return err } - if err != nil { - return err - } - // Create the event stateDB.AddLog(ðtypes.Log{ Address: p.Address(),
precompiles/vesting/integration_test.go+907 −122 modified@@ -17,6 +17,7 @@ import ( "github.com/evmos/evmos/v18/precompiles/vesting" evmosutil "github.com/evmos/evmos/v18/testutil" testutiltx "github.com/evmos/evmos/v18/testutil/tx" + "github.com/evmos/evmos/v18/utils" vestingtypes "github.com/evmos/evmos/v18/x/vesting/types" //nolint:revive // dot imports are fine for Ginkgo @@ -55,6 +56,8 @@ var ( differentAddr = testutiltx.GenerateAddress() // vestingAddr is a new address that is used to test the vesting extension. vestingAddr = testutiltx.GenerateAddress() + // gasPrice to be used on tests txs and calculate the fees + gasPrice = math.NewInt(1e9) ) var _ = Describe("Interacting with the vesting extension", func() { @@ -228,19 +231,22 @@ var _ = Describe("Interacting with the vesting extension", func() { }) Context("to fund a clawback vesting account", func() { + for _, callType := range callTypes { callType := callType - BeforeEach(func() { - if callType.directCall == false { + It(fmt.Sprintf("should fund the vesting when defining only lockup (%s)", callType.name), func() { + if !callType.directCall { + // create authorization to allow contract to spend the funder's (s.address) balance + // when funding a vesting account err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, contractAddr, s.address, vesting.FundVestingAccountMsgURL) Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) } - }) - - It(fmt.Sprintf("should fund the vesting when defining only lockup (%s)", callType.name), func() { s.CreateTestClawbackVestingAccount(s.address, toAddr) - createClawbackArgs := s.BuildCallArgs(callType, contractAddr). + + vestAccInitialBal := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + + fundVestingAccArgs := s.BuildCallArgs(callType, contractAddr). WithMethodName(vesting.FundVestingAccountMethod). WithArgs( s.address, @@ -253,19 +259,200 @@ var _ = Describe("Interacting with the vesting extension", func() { fundClawbackVestingCheck := passCheck. WithExpEvents(vesting.EventTypeFundVestingAccount) - _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, createClawbackArgs, fundClawbackVestingCheck) + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, fundClawbackVestingCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + + // Check the vesting account + // + // NOTE: The vesting account is created with the lockup periods only, since the vesting periods are empty. + // The vesting periods are defaulted to instant vesting, i.e. period length = 0. + s.ExpectVestingAccount(toAddr, defaultPeriods, instantPeriods) + + vestCoinsAmt := math.NewIntFromBigInt(defaultPeriods[0].Amount[0].Amount) + vestAccFinalBal := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(vestAccFinalBal.Amount).To(Equal(vestAccInitialBal.Amount.Add(vestCoinsAmt))) + }) + + It(fmt.Sprintf("should fund the vesting account from a smart contract when defining only lockup (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + s.CreateTestClawbackVestingAccount(contractAddr, toAddr) + // send some funds to the smart contract + // authorization to be able to fund from the smart contract is already in the setup + err = evmosutil.FundAccount(s.ctx, s.app.BankKeeper, contractAddr.Bytes(), sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, math.NewInt(100)))) + Expect(err).ToNot(HaveOccurred(), "error while funding the contract: %v", err) + + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + vestAccInitialBal := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + + // Build and execute the tx to fund the vesting account from a smart contract + fundVestingAccArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.FundVestingAccountMethod). + WithArgs( + contractAddr, + toAddr, + uint64(time.Now().Unix()), + defaultPeriods, + emptyPeriods, + ). + WithGasPrice(gasPrice.BigInt()) + + fundClawbackVestingCheck := passCheck. + WithExpEvents(vesting.EventTypeFundVestingAccount) + + res, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, fundClawbackVestingCheck) Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + fees := gasPrice.MulRaw(res.GasUsed) // Check the vesting account // // NOTE: The vesting account is created with the lockup periods only, since the vesting periods are empty. // The vesting periods are defaulted to instant vesting, i.e. period length = 0. s.ExpectVestingAccount(toAddr, defaultPeriods, instantPeriods) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + + // check the contract's balance was deducted to fund the vesting account + contractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBal.Amount).To(Equal(sdk.ZeroInt())) + + vestCoinsAmt := math.NewIntFromBigInt(defaultPeriods[0].Amount[0].Amount) + vestAccFinalBal := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(vestAccFinalBal.Amount).To(Equal(vestAccInitialBal.Amount.Add(vestCoinsAmt))) + }) + + It(fmt.Sprintf("contract that calls funder - should NOT fund the vesting account with a smart contract different than the contract that calls the precompile (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + counterContract, err := contracts.LoadCounterContract() + Expect(err).ToNot(HaveOccurred()) + + funderContractAddr, err := s.DeployContract(counterContract) + Expect(err).ToNot(HaveOccurred(), "error while deploying the smart contract: %v", err) + + s.CreateTestClawbackVestingAccount(funderContractAddr, toAddr) + // send some funds to the smart contract + // authorization to be able to fund from the smart contract is already in the setup + funderContractInitialAmt := math.NewInt(200) + err = evmosutil.FundAccount(s.ctx, s.app.BankKeeper, funderContractAddr.Bytes(), sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, funderContractInitialAmt))) + Expect(err).ToNot(HaveOccurred(), "error while funding the contract: %v", err) + + // create authorization for tx sender to use funder's balance to fund a vesting account + err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, s.address, funderContractAddr, vesting.FundVestingAccountMsgURL) + Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) + + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + // Build and execute the tx to fund the vesting account from a smart contract + fundVestingAccArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.FundVestingAccountMethod). + WithArgs( + funderContractAddr, + toAddr, + uint64(time.Now().Unix()), + defaultPeriods, + emptyPeriods, + ) + _, _, err = contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, execRevertedCheck) + Expect(err).To(HaveOccurred()) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount.LTE(txSenderInitialBal.Amount)).To(BeTrue()) + + // the balance of the contract that calls the precompile should remain 0 + contractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBal.Amount).To(Equal(sdk.ZeroInt())) + + // the balance of the funder contract should remain unchanged + funderContractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, funderContractAddr.Bytes(), s.bondDenom) + Expect(funderContractFinalBal.Amount).To(Equal(funderContractInitialAmt)) + }) + + It(fmt.Sprintf("fund using a third party EOA - should NOT fund the vesting account even if authorized (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + + // send some funds to the funder, a third party EOA + funderAccAddr, _ := testutiltx.NewAccAddressAndKey() + funderHexAddr := common.BytesToAddress(funderAccAddr) + initialFunderBalance := math.NewInt(200) + err = evmosutil.FundAccount(s.ctx, s.app.BankKeeper, funderAccAddr, sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, initialFunderBalance))) + Expect(err).ToNot(HaveOccurred(), "error while funding the third party EOA: %v", err) + + // create authorization for tx sender to use funder's balance to fund a vesting account + err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, s.address, funderHexAddr, vesting.FundVestingAccountMsgURL) + Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) + + // create clawback vesting account with the corresponding funder + s.CreateTestClawbackVestingAccount(funderHexAddr, toAddr) + + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + // Build and execute the tx to fund the vesting account from a third party EOA + fundVestingAccArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.FundVestingAccountMethod). + WithArgs( + funderHexAddr, + toAddr, + uint64(time.Now().Unix()), + defaultPeriods, + emptyPeriods, + ). + WithGasPrice(gasPrice.BigInt()) + + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, execRevertedCheck) + Expect(err).To(HaveOccurred()) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount.LTE(txSenderInitialBal.Amount)).To(BeTrue()) + + // check the funders's balance remains unchanged + funderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, funderAccAddr, s.bondDenom) + Expect(funderFinalBal.Amount).To(Equal(initialFunderBalance)) + }) + + It(fmt.Sprintf("should NOT fund the vesting with tx origin funds when calling the precompile from a smart contract and WITHOUT authorization (%s)", callType.name), func() { + // when calling from a smart contract + // the funder (s.address) needs to authorize + // for the smart contract to use its funds + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + s.CreateTestClawbackVestingAccount(s.address, toAddr) + fundVestingAccArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.FundVestingAccountMethod). + WithArgs( + s.address, + toAddr, + uint64(time.Now().Unix()), + emptyPeriods, + defaultPeriods, + ) + + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, execRevertedCheck) + Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) }) It(fmt.Sprintf("should fund the vesting when defining only vesting (%s)", callType.name), func() { + // when calling from a smart contract + // the funder (s.address) needs to authorize + // for the smart contract to use its funds + if !callType.directCall { + // create authorization to allow contract to spend the funder's (s.address) balance + // when funding a vesting account + err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, contractAddr, s.address, vesting.FundVestingAccountMsgURL) + Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) + } + s.CreateTestClawbackVestingAccount(s.address, toAddr) - createClawbackArgs := s.BuildCallArgs(callType, contractAddr). + fundVestingAccArgs := s.BuildCallArgs(callType, contractAddr). WithMethodName(vesting.FundVestingAccountMethod). WithArgs( s.address, @@ -278,7 +465,7 @@ var _ = Describe("Interacting with the vesting extension", func() { fundClawbackVestingCheck := passCheck. WithExpEvents(vesting.EventTypeFundVestingAccount) - _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, createClawbackArgs, fundClawbackVestingCheck) + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, fundClawbackVestingCheck) Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) // Check the vesting account @@ -288,8 +475,190 @@ var _ = Describe("Interacting with the vesting extension", func() { s.ExpectVestingAccount(toAddr, instantPeriods, defaultPeriods) }) + Context("Table-driven tests for Withdraw Delegator Rewards", func() { + // testCase is a struct used for cases of contracts calls that have some operation + // performed before and/or after the precompile call + type testCase struct { + transferTo *common.Address + before bool + after bool + } + + var ( + args contracts.CallArgs + funderInitialBal sdk.Coin + vestingAccInitialBal sdk.Coin + contractInitialBalance = math.NewInt(100) + ) + + BeforeEach(func() { + args = s.BuildCallArgs(callType, contractAddr). + WithMethodName("fundVestingAccountAndTransfer"). + WithGasPrice(gasPrice.BigInt()) + + // send some funds to the contract + err := evmosutil.FundAccountWithBaseDenom(s.ctx, s.app.BankKeeper, contractAddr.Bytes(), contractInitialBalance.Int64()) + Expect(err).To(BeNil()) + + s.CreateTestClawbackVestingAccount(s.address, toAddr) + + funderInitialBal = s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + vestingAccInitialBal = s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + + // create authorization to allow contract to spend the funder's (s.address) balance + // when funding a vesting account + err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, contractAddr, s.address, vesting.FundVestingAccountMsgURL) + Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) + }) + + DescribeTable(fmt.Sprintf("should fund the vesting account from tx origin when defining only vesting (%s)", callType.name), func(tc testCase) { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + // if not specified, default the transferTo to the funder address + if tc.transferTo == nil { + tc.transferTo = &s.address + } + fundVestingAccArgs := args. + WithArgs( + s.address, + toAddr, + *tc.transferTo, + uint64(time.Now().Unix()), + emptyPeriods, + defaultPeriods, + tc.before, tc.after, // transfer funds to the funder according to test case + ). + WithGasPrice(gasPrice.BigInt()) + + fundClawbackVestingCheck := passCheck. + WithExpEvents(vesting.EventTypeFundVestingAccount) + + res, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, fundVestingAccArgs, fundClawbackVestingCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + + fees := gasPrice.MulRaw(res.GasUsed) + + transferredToAmt := math.ZeroInt() + for _, transferred := range []bool{tc.before, tc.after} { + if transferred { + transferredToAmt = transferredToAmt.AddRaw(15) + } + } + // Check the vesting account + // + // NOTE: The vesting account is created with the vesting periods only, since the lockup periods are empty. + // The lockup periods are defaulted to instant unlocking, i.e. period length = 0. + s.ExpectVestingAccount(toAddr, instantPeriods, defaultPeriods) + + // check the contract's balance was deducted to fund the vesting account + contractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBal.Amount).To(Equal(contractInitialBalance.Sub(transferredToAmt))) + + // check that the vesting account received the funds + vestCoinsAmt := math.NewIntFromBigInt(defaultPeriods[0].Amount[0].Amount) + vestAccFinalBal := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + expVestAccFinalBal := vestingAccInitialBal.Amount.Add(vestCoinsAmt) + if *tc.transferTo == toAddr { + expVestAccFinalBal = expVestAccFinalBal.Add(transferredToAmt) + } + + Expect(vestAccFinalBal.Amount).To(Equal(expVestAccFinalBal)) + + // check that funder balance is reduced by the fees paid, the amt to fund the vesting account, + // but also got the funds sent from the contract (when corresponds) + funderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + expFunderFinalBal := funderInitialBal.Amount.Sub(fees).Sub(vestCoinsAmt) + if *tc.transferTo == s.address { + expFunderFinalBal = expFunderFinalBal.Add(transferredToAmt) + } + + Expect(funderFinalBal.Amount).To(Equal(expFunderFinalBal)) + }, + Entry("funder balance change before & after precompile call", testCase{ + before: true, + after: true, + }), + Entry("funder balance change before precompile call", testCase{ + before: true, + after: false, + }), + Entry("funder balance change after precompile call", testCase{ + before: false, + after: true, + }), + Entry("vesting acc balance change before & after precompile call", testCase{ + transferTo: &toAddr, + before: true, + after: true, + }), + Entry("vesting acc balance change before precompile call", testCase{ + transferTo: &toAddr, + before: true, + after: false, + }), + Entry("vesting acc balance change after precompile call", testCase{ + transferTo: &toAddr, + before: false, + after: true, + }), + ) + }) + + It(fmt.Sprintf("should fund the vesting account from a smart contract when defining only vesting (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + s.CreateTestClawbackVestingAccount(contractAddr, toAddr) + // send some funds to the smart contract + // authorization is already created in the test setup + err = evmosutil.FundAccount(s.ctx, s.app.BankKeeper, contractAddr.Bytes(), sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, math.NewInt(100)))) + Expect(err).ToNot(HaveOccurred(), "error while funding the contract: %v", err) + + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + // Build and execute the tx to fund the vesting account from a smart contract + createClawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.FundVestingAccountMethod). + WithArgs( + contractAddr, + toAddr, + uint64(time.Now().Unix()), + emptyPeriods, + defaultPeriods, + ). + WithGasPrice(gasPrice.BigInt()) + + fundClawbackVestingCheck := passCheck. + WithExpEvents(vesting.EventTypeFundVestingAccount) + + res, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, createClawbackArgs, fundClawbackVestingCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + fees := gasPrice.MulRaw(res.GasUsed) + + // Check the vesting account + s.ExpectVestingAccount(toAddr, instantPeriods, defaultPeriods) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + + // check the contract's balance was deducted to fund the vesting account + contractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBal.Amount).To(Equal(sdk.ZeroInt())) + }) + It(fmt.Sprintf("should fund the vesting when defining both lockup and vesting (%s)", callType.name), func() { s.CreateTestClawbackVestingAccount(s.address, toAddr) + // funder is an EOA (s.address) + // if calling funding via contract call, + // need auth from funder addr (s.address) + // to the contract address + if !callType.directCall { + err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, contractAddr, s.address, vesting.FundVestingAccountMsgURL) + Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) + } createClawbackArgs := s.BuildCallArgs(callType, contractAddr). WithMethodName(vesting.FundVestingAccountMethod). WithArgs( @@ -310,6 +679,48 @@ var _ = Describe("Interacting with the vesting extension", func() { s.ExpectVestingAccount(toAddr, defaultPeriods, defaultPeriods) }) + It(fmt.Sprintf("should fund the vesting account from a smart contract when defining both lockup and vesting (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + s.CreateTestClawbackVestingAccount(contractAddr, toAddr) + // send some funds to the smart contract + err = evmosutil.FundAccount(s.ctx, s.app.BankKeeper, contractAddr.Bytes(), sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, math.NewInt(100)))) + Expect(err).ToNot(HaveOccurred(), "error while funding the contract: %v", err) + + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + // Build and execute the tx to fund the vesting account from a smart contract + createClawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.FundVestingAccountMethod). + WithArgs( + contractAddr, + toAddr, + uint64(time.Now().Unix()), + defaultPeriods, + defaultPeriods, + ). + WithGasPrice(gasPrice.BigInt()) + + fundClawbackVestingCheck := passCheck. + WithExpEvents(vesting.EventTypeFundVestingAccount) + + res, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, createClawbackArgs, fundClawbackVestingCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + fees := gasPrice.MulRaw(res.GasUsed) + + // Check the vesting account + s.ExpectVestingAccount(toAddr, defaultPeriods, defaultPeriods) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + + // check the contract's balance was deducted to fund the vesting account + contractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBal.Amount).To(Equal(sdk.ZeroInt())) + }) + It(fmt.Sprintf("should not fund the vesting when defining different total coins for lockup and vesting (%s)", callType.name), func() { s.CreateTestClawbackVestingAccount(s.address, toAddr) @@ -546,6 +957,8 @@ var _ = Describe("Interacting with the vesting extension", func() { }) Context("to claw back from a vesting account", func() { + var expClawbackAmt = math.NewInt(1000) + BeforeEach(func() { s.CreateTestClawbackVestingAccount(s.address, toAddr) s.FundTestClawbackVestingAccount() @@ -554,132 +967,504 @@ var _ = Describe("Interacting with the vesting extension", func() { for _, callType := range callTypes { callType := callType - BeforeEach(func() { - if callType.directCall == false { - err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, contractAddr, s.address, vesting.ClawbackMsgURL) - Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) - } - }) - - It(fmt.Sprintf("should claw back from the vesting when sending as the funder (%s)", callType.name), func() { - balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) - Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") - - clawbackArgs := s.BuildCallArgs(callType, contractAddr). - WithMethodName(vesting.ClawbackMethod). - WithArgs( - s.address, - toAddr, - differentAddr, - ) - - clawbackCheck := passCheck. - WithExpEvents(vesting.EventTypeClawback) - - _, ethRes, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) - Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + Context("without authorization", func() { + It(fmt.Sprintf("should NOT claw back from the vesting when sending tx from the funder (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithArgs( + s.address, + toAddr, + differentAddr, + ) - var co vesting.ClawbackOutput - err = s.precompile.UnpackIntoInterface(&co, vesting.ClawbackMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "error while unpacking the clawback output: %v", err) - Expect(co.Coins).To(Equal(balances), "expected different clawback amount") + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, execRevertedCheck) + Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) - balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) - Expect(balancePost.Amount.Int64()).To(Equal(int64(100)), "expected only initial balance after clawback") - balanceReceiver := s.app.BankKeeper.GetBalance(s.ctx, differentAddr.Bytes(), s.bondDenom) - Expect(balanceReceiver.Amount).To(Equal(math.NewInt(1000)), "expected receiver to show different balance after clawback") + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount).To(Equal(balancePre.Amount)) + balanceReceiver := s.app.BankKeeper.GetBalance(s.ctx, differentAddr.Bytes(), s.bondDenom) + Expect(balanceReceiver.Amount).To(Equal(math.ZeroInt())) + }) }) - It(fmt.Sprintf("should return an error when not sending as the funder (%s)", callType.name), func() { - // create and fund new account - differentAddr, differentPriv := testutiltx.NewAddrKey() - err := evmosutil.FundAccountWithBaseDenom(s.ctx, s.app.BankKeeper, differentAddr.Bytes(), 1e18) - Expect(err).ToNot(HaveOccurred(), "error while funding the account: %v", err) - - balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) - Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") - - clawbackArgs := s.BuildCallArgs(callType, contractAddr). - WithMethodName(vesting.ClawbackMethod). - WithPrivKey(differentPriv). - WithArgs( - s.address, - toAddr, - differentAddr, - ) - - clawbackCheck := execRevertedCheck - if callType.directCall { - clawbackCheck = failCheck. - WithErrContains(fmt.Sprintf( - "tx origin address %s does not match the funder address %s", - differentAddr, s.address, - )) - } - - _, _, err = contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) - Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) - if callType.directCall { - Expect(err.Error()).To(ContainSubstring("does not match the funder address")) - } - balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) - Expect(balancePost).To(Equal(balancePre), "expected balance not to have changed") - }) - - It(fmt.Sprintf("should return an error when the vesting does not exist (%s)", callType.name), func() { - // fund the new account - err := evmosutil.FundAccountWithBaseDenom(s.ctx, s.app.BankKeeper, differentAddr.Bytes(), 1e18) - Expect(err).ToNot(HaveOccurred(), "error while funding the account: %v", err) + Context("with authorization", func() { + BeforeEach(func() { + if callType.directCall == false { + err = vesting.CreateGenericAuthz(s.ctx, s.app.AuthzKeeper, contractAddr, s.address, vesting.ClawbackMsgURL) + Expect(err).ToNot(HaveOccurred(), "error while creating the generic authorization: %v", err) + } + }) + + It(fmt.Sprintf("should claw back from the vesting when sending as the funder (%s)", callType.name), func() { + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithArgs( + s.address, + toAddr, + differentAddr, + ) - clawbackArgs := s.BuildCallArgs(callType, contractAddr). - WithMethodName(vesting.ClawbackMethod). - WithArgs( - s.address, - differentAddr, - s.address, + clawbackCheck := passCheck. + WithExpEvents(vesting.EventTypeClawback) + + _, ethRes, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + + var co vesting.ClawbackOutput + err = s.precompile.UnpackIntoInterface(&co, vesting.ClawbackMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "error while unpacking the clawback output: %v", err) + Expect(co.Coins).To(Equal(balances), "expected different clawback amount") + + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount.Int64()).To(Equal(int64(100)), "expected only initial balance after clawback") + balanceReceiver := s.app.BankKeeper.GetBalance(s.ctx, differentAddr.Bytes(), s.bondDenom) + Expect(balanceReceiver.Amount).To(Equal(math.NewInt(1000)), "expected receiver to show different balance after clawback") + }) + + Context("table tests for clawback with state changes", func() { + type testCase struct { + dest common.Address + transferTo *common.Address + before bool + after bool + } + DescribeTable(fmt.Sprintf("smart contract as funder - contract with state changes on destination address - should claw back from the vesting when sending as the funder (%s)", callType.name), func(tc testCase) { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + if tc.transferTo == nil { + tc.transferTo = &tc.dest + } + // change the vesting account funder to be the contract + _, err := s.app.VestingKeeper.UpdateVestingFunder(s.ctx, &vestingtypes.MsgUpdateVestingFunder{ + FunderAddress: sdk.AccAddress(s.address.Bytes()).String(), + NewFunderAddress: sdk.AccAddress(contractAddr.Bytes()).String(), + VestingAddress: sdk.AccAddress(toAddr.Bytes()).String(), + }) + Expect(err).ToNot(HaveOccurred()) + + // fund the contract to make internal transfers + contractInitialBalance := math.NewInt(100) + err = evmosutil.FundAccountWithBaseDenom(s.ctx, s.app.BankKeeper, contractAddr.Bytes(), contractInitialBalance.Int64()) + Expect(err).ToNot(HaveOccurred(), "error while funding the contract: %v", err) + + vestAccInitialBal := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(vestAccInitialBal.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName("clawbackWithTransfer"). + WithArgs( + contractAddr, + toAddr, + tc.dest, + *tc.transferTo, + tc.before, + tc.after, + ) + + clawbackCheck := passCheck. + WithExpEvents(vesting.EventTypeClawback) + + _, ethRes, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + + var co vesting.ClawbackOutput + err = s.precompile.UnpackIntoInterface(&co, vesting.ClawbackMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "error while unpacking the clawback output: %v", err) + Expect(co.Coins).To(Equal(balances), "expected different clawback amount") + + contractTransferredAmt := math.ZeroInt() + for _, transferred := range []bool{tc.before, tc.after} { + if transferred { + contractTransferredAmt = contractTransferredAmt.AddRaw(15) + } + } + + vestAccFinalBalance := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + expVestAccFinalBal := vestAccInitialBal.Amount.Sub(expClawbackAmt) + if *tc.transferTo == toAddr { + expVestAccFinalBal = expVestAccFinalBal.Add(contractTransferredAmt) + } + Expect(vestAccFinalBalance.Amount).To(Equal(expVestAccFinalBal), "expected only initial balance after clawback") + + // contract transfers balances when it is not the destination + if tc.dest == contractAddr { + contractFinalBalance := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBalance.Amount).To(Equal(contractInitialBalance.Add(expClawbackAmt))) + return + } + + balanceDest := s.app.BankKeeper.GetBalance(s.ctx, tc.dest.Bytes(), s.bondDenom) + expBalDest := expClawbackAmt + if *tc.transferTo == tc.dest { + expBalDest = expBalDest.Add(contractTransferredAmt) + } + Expect(balanceDest.Amount).To(Equal(expBalDest), "expected receiver to show different balance after clawback") + + contractFinalBalance := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBalance.Amount).To(Equal(contractInitialBalance.Sub(contractTransferredAmt))) + }, + Entry("funder is the destination address - state changes before & after precompile call", testCase{ + dest: contractAddr, + before: true, + after: true, + }), + Entry("funder is the destination address - state changes before precompile call", testCase{ + dest: contractAddr, + before: true, + after: false, + }), + Entry("funder is the destination address - state changes after precompile call", testCase{ + dest: contractAddr, + before: false, + after: true, + }), + Entry("another address is the destination address - state changes before & after precompile", testCase{ + dest: differentAddr, + before: true, + after: true, + }), + Entry("another address is the destination address - state changes before precompile", testCase{ + dest: differentAddr, + before: true, + after: false, + }), + Entry("another address is the destination address - state changes after precompile", testCase{ + dest: differentAddr, + before: false, + after: true, + }), + Entry("another address is the destination address - transfer to vest acc before & after precompile", testCase{ + dest: differentAddr, + transferTo: &toAddr, + before: true, + after: true, + }), + Entry("another address is the destination address - transfer to vest acc before precompile", testCase{ + dest: differentAddr, + transferTo: &toAddr, + before: true, + after: false, + }), + Entry("another address is the destination address - transfer to vest acc after precompile", testCase{ + dest: differentAddr, + transferTo: &toAddr, + before: false, + after: true, + }), ) + }) + + It(fmt.Sprintf("should claw back from the vesting when sending as the funder with the caller smart contract as destination for the clawed back funds (%s)", callType.name), func() { + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + // check the contract's (destination) intial balance. Should be 0 + contractInitialBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractInitialBal.Amount).To(Equal(sdk.ZeroInt())) + + // get tx sender initial balance + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithArgs( + s.address, + toAddr, + contractAddr, + ). + WithGasPrice(gasPrice.BigInt()) + + clawbackCheck := passCheck. + WithExpEvents(vesting.EventTypeClawback) + + res, ethRes, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).ToNot(HaveOccurred(), "error while calling the contract: %v", err) + + fees := gasPrice.MulRaw(res.GasUsed) + + var co vesting.ClawbackOutput + err = s.precompile.UnpackIntoInterface(&co, vesting.ClawbackMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "error while unpacking the clawback output: %v", err) + Expect(co.Coins).To(Equal(balances), "expected different clawback amount") + + // check clawback account balance + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount.Int64()).To(Equal(int64(100)), "expected only initial balance after clawback") + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + + // check contract's final balance (clawback destination) + contractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(contractFinalBal.Amount).To(Equal(math.NewInt(1000)), "expected receiver to show different balance after clawback") + }) + + It(fmt.Sprintf("clawback with revert after precompile call but before changing contract state - should NOT claw back and revert all balances to initial values (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName("clawbackWithRevert"). + WithArgs( + s.address, + toAddr, + differentAddr, + true, + ) - clawbackCheck := execRevertedCheck - // FIXME: error messages in fail check now work differently! - if callType.directCall { - clawbackCheck = failCheck. - WithErrContains(vestingtypes.ErrNotSubjectToClawback.Error()) - } - - _, _, err = contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) - Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) - if callType.directCall { - Expect(err.Error()).To(ContainSubstring("%s: %s", sdk.AccAddress(differentAddr.Bytes()), vestingtypes.ErrNotSubjectToClawback.Error())) - } - }) + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, execRevertedCheck) + Expect(err).To(HaveOccurred()) + + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount).To(Equal(balancePre.Amount), "expected no balance change") + balanceReceiver := s.app.BankKeeper.GetBalance(s.ctx, differentAddr.Bytes(), s.bondDenom) + Expect(balanceReceiver.Amount).To(Equal(math.ZeroInt())) + }) + + It(fmt.Sprintf("clawback with revert after precompile after changing contract state - should NOT claw back and revert all balances to initial values (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName("clawbackWithRevert"). + WithArgs( + s.address, + toAddr, + differentAddr, + false, + ) - It(fmt.Sprintf("should succeed and return empty Coins when all tokens are vested (%s)", callType.name), func() { - // commit block with time so that vesting has ended - ctx, err := evmosutil.CommitAndCreateNewCtx(s.ctx, s.app, time.Hour*24, nil) - Expect(err).ToNot(HaveOccurred(), "error while committing block: %v", err) - s.ctx = ctx + _, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, execRevertedCheck) + Expect(err).To(HaveOccurred()) + + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount).To(Equal(balancePre.Amount), "expected no balance change") + balanceReceiver := s.app.BankKeeper.GetBalance(s.ctx, differentAddr.Bytes(), s.bondDenom) + Expect(balanceReceiver.Amount).To(Equal(math.ZeroInt())) + }) + + It(fmt.Sprintf("another contract as destination - should clawback from the vesting when sending as the funder with another smart contract as destination for the clawed back funds (%s)", callType.name), func() { + counterContract, err := contracts.LoadCounterContract() + Expect(err).ToNot(HaveOccurred()) + + destContractAddr, err := s.DeployContract(counterContract) + Expect(err).ToNot(HaveOccurred(), "error while deploying the smart contract: %v", err) + + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + // check the contract's (destination) intial balance. Should be 0 + destContractInitialBal := s.app.BankKeeper.GetBalance(s.ctx, destContractAddr.Bytes(), s.bondDenom) + Expect(destContractInitialBal.Amount).To(Equal(sdk.ZeroInt())) + + // get tx sender initial balance + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + clawbackCheck := passCheck. + WithExpEvents(vesting.EventTypeClawback) + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithArgs( + s.address, + toAddr, + destContractAddr, + ). + WithGasPrice(gasPrice.BigInt()) + + res, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).NotTo(HaveOccurred()) + fees := gasPrice.MulRaw(res.GasUsed) + + // check clawback account balance + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount).To(Equal(balancePre.Amount.Sub(expClawbackAmt))) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + + // check caller contract's final balance should be zero + callerContractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(callerContractFinalBal.Amount).To(Equal(math.ZeroInt())) + + // check destination contract's final balance should + // have received the clawback amt + destContractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, destContractAddr.Bytes(), s.bondDenom) + Expect(destContractFinalBal.Amount).To(Equal(destContractInitialBal.Amount.Add(expClawbackAmt))) + }) + + It(fmt.Sprintf("another contract as destination - should claw back from the vesting when sending as the funder with another smart contract as destination and triggering state change on destination contract (%s)", callType.name), func() { + if callType.directCall { + Skip("this should only be run for smart contract calls") + } + counterContract, err := contracts.LoadCounterContract() + Expect(err).ToNot(HaveOccurred()) + + destContractAddr, err := s.DeployContract(counterContract) + Expect(err).ToNot(HaveOccurred(), "error while deploying the smart contract: %v", err) + + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + // check the contract's (destination) intial balance. Should be 0 + destContractInitialBal := s.app.BankKeeper.GetBalance(s.ctx, destContractAddr.Bytes(), s.bondDenom) + Expect(destContractInitialBal.Amount).To(Equal(sdk.ZeroInt())) + + // get tx sender initial balance + txSenderInitialBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName("clawbackWithCounterCall"). + WithArgs( + s.address, + toAddr, + destContractAddr, + ). + WithGasPrice(gasPrice.BigInt()) + + // expect the vesting precompile events and the Counter + // contract's events + clawbackCheck := passCheck. + WithABIEvents(mergeEventMaps( + s.precompile.Events, + counterContract.ABI.Events, + )). + WithExpEvents([]string{ + "Added", "Changed", + vesting.EventTypeClawback, + "Changed", + }...) + + res, _, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).NotTo(HaveOccurred()) + fees := gasPrice.MulRaw(res.GasUsed) + + // check clawback account balance + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost.Amount).To(Equal(balancePre.Amount.Sub(expClawbackAmt))) + + // check that tx signer's balance is reduced by the fees paid + txSenderFinalBal := s.app.BankKeeper.GetBalance(s.ctx, s.address.Bytes(), s.bondDenom) + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + + // check caller contract's final balance should be zero + callerContractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, contractAddr.Bytes(), s.bondDenom) + Expect(callerContractFinalBal.Amount).To(Equal(math.ZeroInt())) + + // check destination contract's final balance should + // have received the clawback amt + destContractFinalBal := s.app.BankKeeper.GetBalance(s.ctx, destContractAddr.Bytes(), s.bondDenom) + Expect(destContractFinalBal.Amount).To(Equal(destContractInitialBal.Amount.Add(expClawbackAmt))) + }) + + It(fmt.Sprintf("should return an error when not sending as the funder (%s)", callType.name), func() { + // create and fund new account + differentAddr, differentPriv := testutiltx.NewAddrKey() + err := evmosutil.FundAccountWithBaseDenom(s.ctx, s.app.BankKeeper, differentAddr.Bytes(), 1e18) + Expect(err).ToNot(HaveOccurred(), "error while funding the account: %v", err) + + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithPrivKey(differentPriv). + WithArgs( + s.address, + toAddr, + differentAddr, + ) - balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) - Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + clawbackCheck := execRevertedCheck + if callType.directCall { + clawbackCheck = failCheck. + WithErrContains(fmt.Sprintf( + "tx origin address %s does not match the funder address %s", + differentAddr, s.address, + )) + } + + _, _, err = contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) + if callType.directCall { + Expect(err.Error()).To(ContainSubstring("does not match the funder address")) + } + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost).To(Equal(balancePre), "expected balance not to have changed") + }) + + It(fmt.Sprintf("should return an error when the vesting does not exist (%s)", callType.name), func() { + // fund the new account + err := evmosutil.FundAccountWithBaseDenom(s.ctx, s.app.BankKeeper, differentAddr.Bytes(), 1e18) + Expect(err).ToNot(HaveOccurred(), "error while funding the account: %v", err) + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithArgs( + s.address, + differentAddr, + s.address, + ) - clawbackArgs := s.BuildCallArgs(callType, contractAddr). - WithMethodName(vesting.ClawbackMethod). - WithArgs( - s.address, - toAddr, - s.address, - ) + clawbackCheck := execRevertedCheck + if callType.directCall { + clawbackCheck = failCheck. + WithErrContains(vestingtypes.ErrNotSubjectToClawback.Error()) + } + + _, _, err = contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, clawbackCheck) + Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) + if callType.directCall { + Expect(err.Error()).To(ContainSubstring("%s: %s", sdk.AccAddress(differentAddr.Bytes()), vestingtypes.ErrNotSubjectToClawback.Error())) + } + }) + + It(fmt.Sprintf("should succeed and return empty Coins when all tokens are vested (%s)", callType.name), func() { + // commit block with time so that vesting has ended + ctx, err := evmosutil.CommitAndCreateNewCtx(s.ctx, s.app, time.Hour*24, nil) + Expect(err).ToNot(HaveOccurred(), "error while committing block: %v", err) + s.ctx = ctx + + balancePre := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePre.Amount).To(Equal(math.NewInt(1100)), "expected different balance after setup") + + clawbackArgs := s.BuildCallArgs(callType, contractAddr). + WithMethodName(vesting.ClawbackMethod). + WithArgs( + s.address, + toAddr, + s.address, + ) - _, ethRes, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, passCheck) - Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) + _, ethRes, err := contracts.CallContractAndCheckLogs(s.ctx, s.app, clawbackArgs, passCheck) + Expect(err).To(HaveOccurred(), "error while calling the contract: %v", err) - var co vesting.ClawbackOutput - err = s.precompile.UnpackIntoInterface(&co, vesting.ClawbackMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "error while unpacking the clawback output: %v", err) - Expect(co.Coins).To(BeEmpty(), "expected empty clawback amount") + var co vesting.ClawbackOutput + err = s.precompile.UnpackIntoInterface(&co, vesting.ClawbackMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "error while unpacking the clawback output: %v", err) + Expect(co.Coins).To(BeEmpty(), "expected empty clawback amount") - balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) - Expect(balancePost).To(Equal(balancePre), "expected balance not to have changed") + balancePost := s.app.BankKeeper.GetBalance(s.ctx, toAddr.Bytes(), s.bondDenom) + Expect(balancePost).To(Equal(balancePre), "expected balance not to have changed") + }) }) } })
precompiles/vesting/testdata/VestingCaller.json+335 −2 modified@@ -109,6 +109,149 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "dest", + "type": "address" + } + ], + "name": "clawbackWithCounterCall", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "coins", + "type": "tuple[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "dest", + "type": "address" + }, + { + "internalType": "bool", + "name": "before", + "type": "bool" + } + ], + "name": "clawbackWithRevert", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "coins", + "type": "tuple[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "dest", + "type": "address" + }, + { + "internalType": "address payable", + "name": "_transferTo", + "type": "address" + }, + { + "internalType": "bool", + "name": "_before", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_after", + "type": "bool" + } + ], + "name": "clawbackWithTransfer", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "coins", + "type": "tuple[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -122,6 +265,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "counter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -233,6 +389,183 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "address payable", + "name": "_transferTo", + "type": "address" + }, + { + "internalType": "uint64", + "name": "startTime", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "int64", + "name": "length", + "type": "int64" + }, + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "amount", + "type": "tuple[]" + } + ], + "internalType": "struct Period[]", + "name": "lockupPeriods", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "int64", + "name": "length", + "type": "int64" + }, + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "amount", + "type": "tuple[]" + } + ], + "internalType": "struct Period[]", + "name": "vestingPeriods", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "transferBefore", + "type": "bool" + }, + { + "internalType": "bool", + "name": "transferAfter", + "type": "bool" + } + ], + "name": "fundVestingAccountAndTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint64", + "name": "startTime", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "int64", + "name": "length", + "type": "int64" + }, + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "amount", + "type": "tuple[]" + } + ], + "internalType": "struct Period[]", + "name": "lockupPeriods", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "int64", + "name": "length", + "type": "int64" + }, + { + "components": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Coin[]", + "name": "amount", + "type": "tuple[]" + } + ], + "internalType": "struct Period[]", + "name": "vestingPeriods", + "type": "tuple[]" + } + ], + "name": "fundVestingAccountWithCounterContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -257,8 +590,8 @@ "type": "function" } ], - "bytecode": "0x608060405234801561001057600080fd5b50611707806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806372e7c9ab1161005b57806372e7c9ab146100ec5780637caef81b1461011c5780639cfef12914610126578063cdb50175146101425761007d565b806327e235e3146100825780634fe1a8df146100b45780635a211064146100d0575b600080fd5b61009c600480360381019061009791906106f5565b61015e565b6040516100ab939291906108ca565b60405180910390f35b6100ce60048036038101906100c991906109bb565b6101f1565b005b6100ea60048036038101906100e591906106f5565b6102c9565b005b61010660048036038101906101019190610a77565b61038f565b6040516101139190610aca565b60405180910390f35b610124610421565b005b610140600480360381019061013b9190610a77565b6104eb565b005b61015c60048036038101906101579190610b24565b6105b7565b005b606080606061080373ffffffffffffffffffffffffffffffffffffffff166327e235e3856040518263ffffffff1660e01b815260040161019e9190610b86565b600060405180830381865afa1580156101bb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906101e49190610e45565b9250925092509193909250565b600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df898989898989896040518863ffffffff1660e01b815260040161023a97969594939291906112e5565b6020604051808303816000875af1158015610259573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027d919061135f565b9050806102bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b69061140f565b60405180910390fd5b5050505050505050565b600061080373ffffffffffffffffffffffffffffffffffffffff16635a211064836040518263ffffffff1660e01b81526004016103069190610b86565b6020604051808303816000875af1158015610325573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610349919061135f565b90508061038b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610382906114a1565b60405180910390fd5b5050565b606061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8585856040518463ffffffff1660e01b81526004016103d0939291906114c1565b6000604051808303816000875af11580156103ef573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061041891906114f8565b90509392505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb50175333060006040518463ffffffff1660e01b815260040161046393929190611550565b6020604051808303816000875af1158015610482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a6919061135f565b9050806104e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104df9061161f565b60405180910390fd5b50565b600061080373ffffffffffffffffffffffffffffffffffffffff16639cfef1298585856040518463ffffffff1660e01b815260040161052c939291906114c1565b6020604051808303816000875af115801561054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056f919061135f565b9050806105b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105a8906116b1565b60405180910390fd5b50505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb501758585856040518463ffffffff1660e01b81526004016105f893929190611550565b6020604051808303816000875af1158015610617573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063b919061135f565b90508061067d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106749061140f565b60405180910390fd5b50505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006106c282610697565b9050919050565b6106d2816106b7565b81146106dd57600080fd5b50565b6000813590506106ef816106c9565b92915050565b60006020828403121561070b5761070a61068d565b5b6000610719848285016106e0565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561078857808201518184015260208101905061076d565b60008484015250505050565b6000601f19601f8301169050919050565b60006107b08261074e565b6107ba8185610759565b93506107ca81856020860161076a565b6107d381610794565b840191505092915050565b6000819050919050565b6107f1816107de565b82525050565b6000604083016000830151848203600086015261081482826107a5565b915050602083015161082960208601826107e8565b508091505092915050565b600061084083836107f7565b905092915050565b6000602082019050919050565b600061086082610722565b61086a818561072d565b93508360208202850161087c8561073e565b8060005b858110156108b857848403895281516108998582610834565b94506108a483610848565b925060208a01995050600181019050610880565b50829750879550505050505092915050565b600060608201905081810360008301526108e48186610855565b905081810360208301526108f88185610855565b9050818103604083015261090c8184610855565b9050949350505050565b600067ffffffffffffffff82169050919050565b61093381610916565b811461093e57600080fd5b50565b6000813590506109508161092a565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261097b5761097a610956565b5b8235905067ffffffffffffffff8111156109985761099761095b565b5b6020830191508360208202830111156109b4576109b3610960565b5b9250929050565b600080600080600080600060a0888a0312156109da576109d961068d565b5b60006109e88a828b016106e0565b97505060206109f98a828b016106e0565b9650506040610a0a8a828b01610941565b955050606088013567ffffffffffffffff811115610a2b57610a2a610692565b5b610a378a828b01610965565b9450945050608088013567ffffffffffffffff811115610a5a57610a59610692565b5b610a668a828b01610965565b925092505092959891949750929550565b600080600060608486031215610a9057610a8f61068d565b5b6000610a9e868287016106e0565b9350506020610aaf868287016106e0565b9250506040610ac0868287016106e0565b9150509250925092565b60006020820190508181036000830152610ae48184610855565b905092915050565b60008115159050919050565b610b0181610aec565b8114610b0c57600080fd5b50565b600081359050610b1e81610af8565b92915050565b600080600060608486031215610b3d57610b3c61068d565b5b6000610b4b868287016106e0565b9350506020610b5c868287016106e0565b9250506040610b6d86828701610b0f565b9150509250925092565b610b80816106b7565b82525050565b6000602082019050610b9b6000830184610b77565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610bd982610794565b810181811067ffffffffffffffff82111715610bf857610bf7610ba1565b5b80604052505050565b6000610c0b610683565b9050610c178282610bd0565b919050565b600067ffffffffffffffff821115610c3757610c36610ba1565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff821115610c7257610c71610ba1565b5b610c7b82610794565b9050602081019050919050565b6000610c9b610c9684610c57565b610c01565b905082815260208101848484011115610cb757610cb6610c52565b5b610cc284828561076a565b509392505050565b600082601f830112610cdf57610cde610956565b5b8151610cef848260208601610c88565b91505092915050565b610d01816107de565b8114610d0c57600080fd5b50565b600081519050610d1e81610cf8565b92915050565b600060408284031215610d3a57610d39610c48565b5b610d446040610c01565b9050600082015167ffffffffffffffff811115610d6457610d63610c4d565b5b610d7084828501610cca565b6000830152506020610d8484828501610d0f565b60208301525092915050565b6000610da3610d9e84610c1c565b610c01565b90508083825260208201905060208402830185811115610dc657610dc5610960565b5b835b81811015610e0d57805167ffffffffffffffff811115610deb57610dea610956565b5b808601610df88982610d24565b85526020850194505050602081019050610dc8565b5050509392505050565b600082601f830112610e2c57610e2b610956565b5b8151610e3c848260208601610d90565b91505092915050565b600080600060608486031215610e5e57610e5d61068d565b5b600084015167ffffffffffffffff811115610e7c57610e7b610692565b5b610e8886828701610e17565b935050602084015167ffffffffffffffff811115610ea957610ea8610692565b5b610eb586828701610e17565b925050604084015167ffffffffffffffff811115610ed657610ed5610692565b5b610ee286828701610e17565b9150509250925092565b610ef581610916565b82525050565b600082825260208201905092915050565b6000819050919050565b60008160070b9050919050565b610f2c81610f16565b8114610f3757600080fd5b50565b600081359050610f4981610f23565b92915050565b6000610f5e6020840184610f3a565b905092915050565b610f6f81610f16565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112610fa157610fa0610f7f565b5b83810192508235915060208301925067ffffffffffffffff821115610fc957610fc8610f75565b5b602082023603831315610fdf57610fde610f7a565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b6000808335600160200384360303811261101f5761101e610f7f565b5b83810192508235915060208301925067ffffffffffffffff82111561104757611046610f75565b5b60018202360383131561105d5761105c610f7a565b5b509250929050565b82818337600083830152505050565b60006110808385610759565b935061108d838584611065565b61109683610794565b840190509392505050565b6000813590506110b081610cf8565b92915050565b60006110c560208401846110a1565b905092915050565b6000604083016110e06000840184611002565b85830360008701526110f3838284611074565b9250505061110460208401846110b6565b61111160208601826107e8565b508091505092915050565b600061112883836110cd565b905092915050565b60008235600160400383360303811261114c5761114b610f7f565b5b82810191505092915050565b6000602082019050919050565b60006111718385610fe7565b93508360208402850161118384610ff8565b8060005b878110156111c757848403895261119e8284611130565b6111a8858261111c565b94506111b383611158565b925060208a01995050600181019050611187565b50829750879450505050509392505050565b6000604083016111ec6000840184610f4f565b6111f96000860182610f66565b506112076020840184610f84565b858303602087015261121a838284611165565b925050508091505092915050565b600061123483836111d9565b905092915050565b60008235600160400383360303811261125857611257610f7f565b5b82810191505092915050565b6000602082019050919050565b600061127d8385610efb565b93508360208402850161128f84610f0c565b8060005b878110156112d35784840389526112aa828461123c565b6112b48582611228565b94506112bf83611264565b925060208a01995050600181019050611293565b50829750879450505050509392505050565b600060a0820190506112fa600083018a610b77565b6113076020830189610b77565b6113146040830188610eec565b8181036060830152611327818688611271565b9050818103608083015261133c818486611271565b905098975050505050505050565b60008151905061135981610af8565b92915050565b6000602082840312156113755761137461068d565b5b60006113838482850161134a565b91505092915050565b600082825260208201905092915050565b7f56657374696e6743616c6c65723a2063726561746520636c61776261636b207660008201527f657374696e67206163636f756e74206661696c65640000000000000000000000602082015250565b60006113f960358361138c565b91506114048261139d565b604082019050919050565b60006020820190508181036000830152611428816113ec565b9050919050565b7f56657374696e6743616c6c65723a20636f6e7665727420746f20636c6177626160008201527f636b2076657374696e67206163636f756e74206661696c656400000000000000602082015250565b600061148b60398361138c565b91506114968261142f565b604082019050919050565b600060208201905081810360008301526114ba8161147e565b9050919050565b60006060820190506114d66000830186610b77565b6114e36020830185610b77565b6114f06040830184610b77565b949350505050565b60006020828403121561150e5761150d61068d565b5b600082015167ffffffffffffffff81111561152c5761152b610692565b5b61153884828501610e17565b91505092915050565b61154a81610aec565b82525050565b60006060820190506115656000830186610b77565b6115726020830185610b77565b61157f6040830184611541565b949350505050565b7f56657374696e6743616c6c65723a2063726561746520636c61776261636b207660008201527f657374696e67206163636f756e7420666f7220636f6e7472616374206661696c60208201527f6564000000000000000000000000000000000000000000000000000000000000604082015250565b600061160960428361138c565b915061161482611587565b606082019050919050565b60006020820190508181036000830152611638816115fc565b9050919050565b7f56657374696e6743616c6c65723a207570646174652076657374696e6720667560008201527f6e646572206661696c6564000000000000000000000000000000000000000000602082015250565b600061169b602b8361138c565b91506116a68261163f565b604082019050919050565b600060208201905081810360008301526116ca8161168e565b905091905056fea2646970667358221220b5591174fd0eae8c3194a72e4046b55353e35d6f0b4613d06bca7876629b922764736f6c63430008130033", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c806372e7c9ab1161005b57806372e7c9ab146100ec5780637caef81b1461011c5780639cfef12914610126578063cdb50175146101425761007d565b806327e235e3146100825780634fe1a8df146100b45780635a211064146100d0575b600080fd5b61009c600480360381019061009791906106f5565b61015e565b6040516100ab939291906108ca565b60405180910390f35b6100ce60048036038101906100c991906109bb565b6101f1565b005b6100ea60048036038101906100e591906106f5565b6102c9565b005b61010660048036038101906101019190610a77565b61038f565b6040516101139190610aca565b60405180910390f35b610124610421565b005b610140600480360381019061013b9190610a77565b6104eb565b005b61015c60048036038101906101579190610b24565b6105b7565b005b606080606061080373ffffffffffffffffffffffffffffffffffffffff166327e235e3856040518263ffffffff1660e01b815260040161019e9190610b86565b600060405180830381865afa1580156101bb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906101e49190610e45565b9250925092509193909250565b600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df898989898989896040518863ffffffff1660e01b815260040161023a97969594939291906112e5565b6020604051808303816000875af1158015610259573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027d919061135f565b9050806102bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b69061140f565b60405180910390fd5b5050505050505050565b600061080373ffffffffffffffffffffffffffffffffffffffff16635a211064836040518263ffffffff1660e01b81526004016103069190610b86565b6020604051808303816000875af1158015610325573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610349919061135f565b90508061038b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610382906114a1565b60405180910390fd5b5050565b606061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8585856040518463ffffffff1660e01b81526004016103d0939291906114c1565b6000604051808303816000875af11580156103ef573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061041891906114f8565b90509392505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb50175333060006040518463ffffffff1660e01b815260040161046393929190611550565b6020604051808303816000875af1158015610482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a6919061135f565b9050806104e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104df9061161f565b60405180910390fd5b50565b600061080373ffffffffffffffffffffffffffffffffffffffff16639cfef1298585856040518463ffffffff1660e01b815260040161052c939291906114c1565b6020604051808303816000875af115801561054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056f919061135f565b9050806105b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105a8906116b1565b60405180910390fd5b50505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb501758585856040518463ffffffff1660e01b81526004016105f893929190611550565b6020604051808303816000875af1158015610617573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063b919061135f565b90508061067d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106749061140f565b60405180910390fd5b50505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006106c282610697565b9050919050565b6106d2816106b7565b81146106dd57600080fd5b50565b6000813590506106ef816106c9565b92915050565b60006020828403121561070b5761070a61068d565b5b6000610719848285016106e0565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561078857808201518184015260208101905061076d565b60008484015250505050565b6000601f19601f8301169050919050565b60006107b08261074e565b6107ba8185610759565b93506107ca81856020860161076a565b6107d381610794565b840191505092915050565b6000819050919050565b6107f1816107de565b82525050565b6000604083016000830151848203600086015261081482826107a5565b915050602083015161082960208601826107e8565b508091505092915050565b600061084083836107f7565b905092915050565b6000602082019050919050565b600061086082610722565b61086a818561072d565b93508360208202850161087c8561073e565b8060005b858110156108b857848403895281516108998582610834565b94506108a483610848565b925060208a01995050600181019050610880565b50829750879550505050505092915050565b600060608201905081810360008301526108e48186610855565b905081810360208301526108f88185610855565b9050818103604083015261090c8184610855565b9050949350505050565b600067ffffffffffffffff82169050919050565b61093381610916565b811461093e57600080fd5b50565b6000813590506109508161092a565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261097b5761097a610956565b5b8235905067ffffffffffffffff8111156109985761099761095b565b5b6020830191508360208202830111156109b4576109b3610960565b5b9250929050565b600080600080600080600060a0888a0312156109da576109d961068d565b5b60006109e88a828b016106e0565b97505060206109f98a828b016106e0565b9650506040610a0a8a828b01610941565b955050606088013567ffffffffffffffff811115610a2b57610a2a610692565b5b610a378a828b01610965565b9450945050608088013567ffffffffffffffff811115610a5a57610a59610692565b5b610a668a828b01610965565b925092505092959891949750929550565b600080600060608486031215610a9057610a8f61068d565b5b6000610a9e868287016106e0565b9350506020610aaf868287016106e0565b9250506040610ac0868287016106e0565b9150509250925092565b60006020820190508181036000830152610ae48184610855565b905092915050565b60008115159050919050565b610b0181610aec565b8114610b0c57600080fd5b50565b600081359050610b1e81610af8565b92915050565b600080600060608486031215610b3d57610b3c61068d565b5b6000610b4b868287016106e0565b9350506020610b5c868287016106e0565b9250506040610b6d86828701610b0f565b9150509250925092565b610b80816106b7565b82525050565b6000602082019050610b9b6000830184610b77565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610bd982610794565b810181811067ffffffffffffffff82111715610bf857610bf7610ba1565b5b80604052505050565b6000610c0b610683565b9050610c178282610bd0565b919050565b600067ffffffffffffffff821115610c3757610c36610ba1565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff821115610c7257610c71610ba1565b5b610c7b82610794565b9050602081019050919050565b6000610c9b610c9684610c57565b610c01565b905082815260208101848484011115610cb757610cb6610c52565b5b610cc284828561076a565b509392505050565b600082601f830112610cdf57610cde610956565b5b8151610cef848260208601610c88565b91505092915050565b610d01816107de565b8114610d0c57600080fd5b50565b600081519050610d1e81610cf8565b92915050565b600060408284031215610d3a57610d39610c48565b5b610d446040610c01565b9050600082015167ffffffffffffffff811115610d6457610d63610c4d565b5b610d7084828501610cca565b6000830152506020610d8484828501610d0f565b60208301525092915050565b6000610da3610d9e84610c1c565b610c01565b90508083825260208201905060208402830185811115610dc657610dc5610960565b5b835b81811015610e0d57805167ffffffffffffffff811115610deb57610dea610956565b5b808601610df88982610d24565b85526020850194505050602081019050610dc8565b5050509392505050565b600082601f830112610e2c57610e2b610956565b5b8151610e3c848260208601610d90565b91505092915050565b600080600060608486031215610e5e57610e5d61068d565b5b600084015167ffffffffffffffff811115610e7c57610e7b610692565b5b610e8886828701610e17565b935050602084015167ffffffffffffffff811115610ea957610ea8610692565b5b610eb586828701610e17565b925050604084015167ffffffffffffffff811115610ed657610ed5610692565b5b610ee286828701610e17565b9150509250925092565b610ef581610916565b82525050565b600082825260208201905092915050565b6000819050919050565b60008160070b9050919050565b610f2c81610f16565b8114610f3757600080fd5b50565b600081359050610f4981610f23565b92915050565b6000610f5e6020840184610f3a565b905092915050565b610f6f81610f16565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112610fa157610fa0610f7f565b5b83810192508235915060208301925067ffffffffffffffff821115610fc957610fc8610f75565b5b602082023603831315610fdf57610fde610f7a565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b6000808335600160200384360303811261101f5761101e610f7f565b5b83810192508235915060208301925067ffffffffffffffff82111561104757611046610f75565b5b60018202360383131561105d5761105c610f7a565b5b509250929050565b82818337600083830152505050565b60006110808385610759565b935061108d838584611065565b61109683610794565b840190509392505050565b6000813590506110b081610cf8565b92915050565b60006110c560208401846110a1565b905092915050565b6000604083016110e06000840184611002565b85830360008701526110f3838284611074565b9250505061110460208401846110b6565b61111160208601826107e8565b508091505092915050565b600061112883836110cd565b905092915050565b60008235600160400383360303811261114c5761114b610f7f565b5b82810191505092915050565b6000602082019050919050565b60006111718385610fe7565b93508360208402850161118384610ff8565b8060005b878110156111c757848403895261119e8284611130565b6111a8858261111c565b94506111b383611158565b925060208a01995050600181019050611187565b50829750879450505050509392505050565b6000604083016111ec6000840184610f4f565b6111f96000860182610f66565b506112076020840184610f84565b858303602087015261121a838284611165565b925050508091505092915050565b600061123483836111d9565b905092915050565b60008235600160400383360303811261125857611257610f7f565b5b82810191505092915050565b6000602082019050919050565b600061127d8385610efb565b93508360208402850161128f84610f0c565b8060005b878110156112d35784840389526112aa828461123c565b6112b48582611228565b94506112bf83611264565b925060208a01995050600181019050611293565b50829750879450505050509392505050565b600060a0820190506112fa600083018a610b77565b6113076020830189610b77565b6113146040830188610eec565b8181036060830152611327818688611271565b9050818103608083015261133c818486611271565b905098975050505050505050565b60008151905061135981610af8565b92915050565b6000602082840312156113755761137461068d565b5b60006113838482850161134a565b91505092915050565b600082825260208201905092915050565b7f56657374696e6743616c6c65723a2063726561746520636c61776261636b207660008201527f657374696e67206163636f756e74206661696c65640000000000000000000000602082015250565b60006113f960358361138c565b91506114048261139d565b604082019050919050565b60006020820190508181036000830152611428816113ec565b9050919050565b7f56657374696e6743616c6c65723a20636f6e7665727420746f20636c6177626160008201527f636b2076657374696e67206163636f756e74206661696c656400000000000000602082015250565b600061148b60398361138c565b91506114968261142f565b604082019050919050565b600060208201905081810360008301526114ba8161147e565b9050919050565b60006060820190506114d66000830186610b77565b6114e36020830185610b77565b6114f06040830184610b77565b949350505050565b60006020828403121561150e5761150d61068d565b5b600082015167ffffffffffffffff81111561152c5761152b610692565b5b61153884828501610e17565b91505092915050565b61154a81610aec565b82525050565b60006060820190506115656000830186610b77565b6115726020830185610b77565b61157f6040830184611541565b949350505050565b7f56657374696e6743616c6c65723a2063726561746520636c61776261636b207660008201527f657374696e67206163636f756e7420666f7220636f6e7472616374206661696c60208201527f6564000000000000000000000000000000000000000000000000000000000000604082015250565b600061160960428361138c565b915061161482611587565b606082019050919050565b60006020820190508181036000830152611638816115fc565b9050919050565b7f56657374696e6743616c6c65723a207570646174652076657374696e6720667560008201527f6e646572206661696c6564000000000000000000000000000000000000000000602082015250565b600061169b602b8361138c565b91506116a68261163f565b604082019050919050565b600060208201905081810360008301526116ca8161168e565b905091905056fea2646970667358221220b5591174fd0eae8c3194a72e4046b55353e35d6f0b4613d06bca7876629b922764736f6c63430008130033", + "bytecode": "0x608060405234801561001057600080fd5b506127ac806100206000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636c49d3031161008c5780638e292e40116100665780638e292e40146101fe5780639cfef1291461022e578063cdb501751461024a578063fc9c1a8714610266576100cf565b80636c49d303146101a857806372e7c9ab146101c45780637caef81b146101f4576100cf565b806303f4be50146100d45780631e9178bb1461010457806327e235e3146101205780634fe1a8df146101525780635a2110641461016e57806361bc221a1461018a575b600080fd5b6100ee60048036038101906100e99190611233565b610296565b6040516100fb919061142e565b60405180910390f35b61011e6004803603810190610119919061156b565b61041c565b005b61013a60048036038101906101359190611662565b61068f565b6040516101499392919061168f565b60405180910390f35b61016c600480360381019061016791906116db565b610722565b005b61018860048036038101906101839190611662565b610828565b005b6101926108ee565b60405161019f91906117a6565b60405180910390f35b6101c260048036038101906101bd91906116db565b6108f4565b005b6101de60048036038101906101d99190611233565b610ac0565b6040516101eb919061142e565b60405180910390f35b6101fc610b80565b005b610218600480360381019061021391906117c1565b610c4a565b604051610225919061142e565b60405180910390f35b61024860048036038101906102439190611233565b610d94565b005b610264600480360381019061025f9190611828565b610e60565b005b610280600480360381019061027b919061187b565b610f2c565b60405161028d919061142e565b60405180910390f35b606060008290508073ffffffffffffffffffffffffffffffffffffffff16634f2be91f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156102e557600080fd5b505af11580156102f9573d6000803e3d6000fd5b5050505060008081548092919061030f90611937565b919050555061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8686866040518463ffffffff1660e01b81526004016103539392919061198e565b6000604051808303816000875af1158015610372573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061039b9190611c69565b91508073ffffffffffffffffffffffffffffffffffffffff16636deebae36040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103e557600080fd5b505af11580156103f9573d6000803e3d6000fd5b5050505060008081548092919061040f90611cb2565b9190505550509392505050565b81156104e85760008081548092919061043490611937565b919050555060008873ffffffffffffffffffffffffffffffffffffffff16600f60405161046090611d0c565b60006040518083038185875af1925050503d806000811461049d576040519150601f19603f3d011682016040523d82523d6000602084013e6104a2565b606091505b50509050806104e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104dd90611d7e565b60405180910390fd5b505b600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df8c8c8b8b8b8b8b6040518863ffffffff1660e01b815260040161053197969594939291906121f6565b6020604051808303816000875af1158015610550573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105749190612270565b9050806105b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ad9061230f565b60405180910390fd5b81156106825760008973ffffffffffffffffffffffffffffffffffffffff16600f6040516105e390611d0c565b60006040518083038185875af1925050503d8060008114610620576040519150601f19603f3d011682016040523d82523d6000602084013e610625565b606091505b5050905080610669576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066090611d7e565b60405180910390fd5b60008081548092919061067b90611937565b9190505550505b5050505050505050505050565b606080606061080373ffffffffffffffffffffffffffffffffffffffff166327e235e3856040518263ffffffff1660e01b81526004016106cf919061232f565b600060405180830381865afa1580156106ec573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610715919061234a565b9250925092509193909250565b60008081548092919061073490611937565b9190505550600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df898989898989896040518863ffffffff1660e01b815260040161078297969594939291906123f1565b6020604051808303816000875af11580156107a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c59190612270565b905080610807576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107fe9061230f565b60405180910390fd5b60008081548092919061081990611cb2565b91905055505050505050505050565b600061080373ffffffffffffffffffffffffffffffffffffffff16635a211064836040518263ffffffff1660e01b8152600401610865919061232f565b6020604051808303816000875af1158015610884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a89190612270565b9050806108ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906124c8565b60405180910390fd5b5050565b60005481565b60008790508073ffffffffffffffffffffffffffffffffffffffff16634f2be91f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561094157600080fd5b505af1158015610955573d6000803e3d6000fd5b5050505060008081548092919061096b90611937565b9190505550600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df8a8a8a8a8a8a8a6040518863ffffffff1660e01b81526004016109b997969594939291906123f1565b6020604051808303816000875af11580156109d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fc9190612270565b905080610a3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a359061230f565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16636deebae36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610a8657600080fd5b505af1158015610a9a573d6000803e3d6000fd5b50505050600080815480929190610ab090611cb2565b9190505550505050505050505050565b6060600080815480929190610ad490611937565b919050555061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8585856040518463ffffffff1660e01b8152600401610b189392919061198e565b6000604051808303816000875af1158015610b37573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b609190611c69565b9050600080815480929190610b7490611cb2565b91905055509392505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb50175333060006040518463ffffffff1660e01b8152600401610bc2939291906124f7565b6020604051808303816000875af1158015610be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c059190612270565b905080610c47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3e906125c6565b60405180910390fd5b50565b6060600080815480929190610c5e90611937565b919050555061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8686866040518463ffffffff1660e01b8152600401610ca29392919061198e565b6000604051808303816000875af1158015610cc1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610cea9190611c69565b90508115610d34576000610d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2a90612632565b60405180910390fd5b5b600080815480929190610d4690611cb2565b91905055506000610d8c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8390612632565b60405180910390fd5b949350505050565b600061080373ffffffffffffffffffffffffffffffffffffffff16639cfef1298585856040518463ffffffff1660e01b8152600401610dd59392919061198e565b6020604051808303816000875af1158015610df4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e189190612270565b905080610e5a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e51906126c4565b60405180910390fd5b50505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb501758585856040518463ffffffff1660e01b8152600401610ea1939291906124f7565b6020604051808303816000875af1158015610ec0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee49190612270565b905080610f26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1d9061230f565b60405180910390fd5b50505050565b6060821561102e57600080815480929190610f4690611937565b91905055503073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161461102d5760008473ffffffffffffffffffffffffffffffffffffffff16600f604051610fa590611d0c565b60006040518083038185875af1925050503d8060008114610fe2576040519150601f19603f3d011682016040523d82523d6000602084013e610fe7565b606091505b505090508061102b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102290612756565b60405180910390fd5b505b5b61080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8888886040518463ffffffff1660e01b815260040161106d9392919061198e565b6000604051808303816000875af115801561108c573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906110b59190611c69565b905081156111b7576000808154809291906110cf90611937565b91905055503073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16146111b65760008473ffffffffffffffffffffffffffffffffffffffff16600f60405161112e90611d0c565b60006040518083038185875af1925050503d806000811461116b576040519150601f19603f3d011682016040523d82523d6000602084013e611170565b606091505b50509050806111b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111ab90612756565b60405180910390fd5b505b5b9695505050505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611200826111d5565b9050919050565b611210816111f5565b811461121b57600080fd5b50565b60008135905061122d81611207565b92915050565b60008060006060848603121561124c5761124b6111cb565b5b600061125a8682870161121e565b935050602061126b8682870161121e565b925050604061127c8682870161121e565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156112ec5780820151818401526020810190506112d1565b60008484015250505050565b6000601f19601f8301169050919050565b6000611314826112b2565b61131e81856112bd565b935061132e8185602086016112ce565b611337816112f8565b840191505092915050565b6000819050919050565b61135581611342565b82525050565b600060408301600083015184820360008601526113788282611309565b915050602083015161138d602086018261134c565b508091505092915050565b60006113a4838361135b565b905092915050565b6000602082019050919050565b60006113c482611286565b6113ce8185611291565b9350836020820285016113e0856112a2565b8060005b8581101561141c57848403895281516113fd8582611398565b9450611408836113ac565b925060208a019950506001810190506113e4565b50829750879550505050505092915050565b6000602082019050818103600083015261144881846113b9565b905092915050565b600061145b826111d5565b9050919050565b61146b81611450565b811461147657600080fd5b50565b60008135905061148881611462565b92915050565b600067ffffffffffffffff82169050919050565b6114ab8161148e565b81146114b657600080fd5b50565b6000813590506114c8816114a2565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126114f3576114f26114ce565b5b8235905067ffffffffffffffff8111156115105761150f6114d3565b5b60208301915083602082028301111561152c5761152b6114d8565b5b9250929050565b60008115159050919050565b61154881611533565b811461155357600080fd5b50565b6000813590506115658161153f565b92915050565b6000806000806000806000806000806101008b8d03121561158f5761158e6111cb565b5b600061159d8d828e01611479565b9a505060206115ae8d828e0161121e565b99505060406115bf8d828e01611479565b98505060606115d08d828e016114b9565b97505060808b013567ffffffffffffffff8111156115f1576115f06111d0565b5b6115fd8d828e016114dd565b965096505060a08b013567ffffffffffffffff8111156116205761161f6111d0565b5b61162c8d828e016114dd565b945094505060c061163f8d828e01611556565b92505060e06116508d828e01611556565b9150509295989b9194979a5092959850565b600060208284031215611678576116776111cb565b5b60006116868482850161121e565b91505092915050565b600060608201905081810360008301526116a981866113b9565b905081810360208301526116bd81856113b9565b905081810360408301526116d181846113b9565b9050949350505050565b600080600080600080600060a0888a0312156116fa576116f96111cb565b5b60006117088a828b0161121e565b97505060206117198a828b0161121e565b965050604061172a8a828b016114b9565b955050606088013567ffffffffffffffff81111561174b5761174a6111d0565b5b6117578a828b016114dd565b9450945050608088013567ffffffffffffffff81111561177a576117796111d0565b5b6117868a828b016114dd565b925092505092959891949750929550565b6117a081611342565b82525050565b60006020820190506117bb6000830184611797565b92915050565b600080600080608085870312156117db576117da6111cb565b5b60006117e98782880161121e565b94505060206117fa8782880161121e565b935050604061180b8782880161121e565b925050606061181c87828801611556565b91505092959194509250565b600080600060608486031215611841576118406111cb565b5b600061184f8682870161121e565b93505060206118608682870161121e565b925050604061187186828701611556565b9150509250925092565b60008060008060008060c08789031215611898576118976111cb565b5b60006118a689828a0161121e565b96505060206118b789828a0161121e565b95505060406118c889828a0161121e565b94505060606118d989828a01611479565b93505060806118ea89828a01611556565b92505060a06118fb89828a01611556565b9150509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061194282611342565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361197457611973611908565b5b600182019050919050565b611988816111f5565b82525050565b60006060820190506119a3600083018661197f565b6119b0602083018561197f565b6119bd604083018461197f565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6119fd826112f8565b810181811067ffffffffffffffff82111715611a1c57611a1b6119c5565b5b80604052505050565b6000611a2f6111c1565b9050611a3b82826119f4565b919050565b600067ffffffffffffffff821115611a5b57611a5a6119c5565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff821115611a9657611a956119c5565b5b611a9f826112f8565b9050602081019050919050565b6000611abf611aba84611a7b565b611a25565b905082815260208101848484011115611adb57611ada611a76565b5b611ae68482856112ce565b509392505050565b600082601f830112611b0357611b026114ce565b5b8151611b13848260208601611aac565b91505092915050565b611b2581611342565b8114611b3057600080fd5b50565b600081519050611b4281611b1c565b92915050565b600060408284031215611b5e57611b5d611a6c565b5b611b686040611a25565b9050600082015167ffffffffffffffff811115611b8857611b87611a71565b5b611b9484828501611aee565b6000830152506020611ba884828501611b33565b60208301525092915050565b6000611bc7611bc284611a40565b611a25565b90508083825260208201905060208402830185811115611bea57611be96114d8565b5b835b81811015611c3157805167ffffffffffffffff811115611c0f57611c0e6114ce565b5b808601611c1c8982611b48565b85526020850194505050602081019050611bec565b5050509392505050565b600082601f830112611c5057611c4f6114ce565b5b8151611c60848260208601611bb4565b91505092915050565b600060208284031215611c7f57611c7e6111cb565b5b600082015167ffffffffffffffff811115611c9d57611c9c6111d0565b5b611ca984828501611c3b565b91505092915050565b6000611cbd82611342565b915060008203611cd057611ccf611908565b5b600182039050919050565b600081905092915050565b50565b6000611cf6600083611cdb565b9150611d0182611ce6565b600082019050919050565b6000611d1782611ce9565b9150819050919050565b600082825260208201905092915050565b7f4661696c656420746f2073656e6420457468657220746f2066756e6465720000600082015250565b6000611d68601e83611d21565b9150611d7382611d32565b602082019050919050565b60006020820190508181036000830152611d9781611d5b565b9050919050565b6000819050919050565b6000611dc3611dbe611db9846111d5565b611d9e565b6111d5565b9050919050565b6000611dd582611da8565b9050919050565b6000611de782611dca565b9050919050565b611df781611ddc565b82525050565b611e068161148e565b82525050565b600082825260208201905092915050565b6000819050919050565b60008160070b9050919050565b611e3d81611e27565b8114611e4857600080fd5b50565b600081359050611e5a81611e34565b92915050565b6000611e6f6020840184611e4b565b905092915050565b611e8081611e27565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112611eb257611eb1611e90565b5b83810192508235915060208301925067ffffffffffffffff821115611eda57611ed9611e86565b5b602082023603831315611ef057611eef611e8b565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112611f3057611f2f611e90565b5b83810192508235915060208301925067ffffffffffffffff821115611f5857611f57611e86565b5b600182023603831315611f6e57611f6d611e8b565b5b509250929050565b82818337600083830152505050565b6000611f9183856112bd565b9350611f9e838584611f76565b611fa7836112f8565b840190509392505050565b600081359050611fc181611b1c565b92915050565b6000611fd66020840184611fb2565b905092915050565b600060408301611ff16000840184611f13565b8583036000870152612004838284611f85565b925050506120156020840184611fc7565b612022602086018261134c565b508091505092915050565b60006120398383611fde565b905092915050565b60008235600160400383360303811261205d5761205c611e90565b5b82810191505092915050565b6000602082019050919050565b60006120828385611ef8565b93508360208402850161209484611f09565b8060005b878110156120d85784840389526120af8284612041565b6120b9858261202d565b94506120c483612069565b925060208a01995050600181019050612098565b50829750879450505050509392505050565b6000604083016120fd6000840184611e60565b61210a6000860182611e77565b506121186020840184611e95565b858303602087015261212b838284612076565b925050508091505092915050565b600061214583836120ea565b905092915050565b60008235600160400383360303811261216957612168611e90565b5b82810191505092915050565b6000602082019050919050565b600061218e8385611e0c565b9350836020840285016121a084611e1d565b8060005b878110156121e45784840389526121bb828461214d565b6121c58582612139565b94506121d083612175565b925060208a019950506001810190506121a4565b50829750879450505050509392505050565b600060a08201905061220b600083018a611dee565b612218602083018961197f565b6122256040830188611dfd565b8181036060830152612238818688612182565b9050818103608083015261224d818486612182565b905098975050505050505050565b60008151905061226a8161153f565b92915050565b600060208284031215612286576122856111cb565b5b60006122948482850161225b565b91505092915050565b7f56657374696e6743616c6c65723a2063726561746520636c61776261636b207660008201527f657374696e67206163636f756e74206661696c65640000000000000000000000602082015250565b60006122f9603583611d21565b91506123048261229d565b604082019050919050565b60006020820190508181036000830152612328816122ec565b9050919050565b6000602082019050612344600083018461197f565b92915050565b600080600060608486031215612363576123626111cb565b5b600084015167ffffffffffffffff811115612381576123806111d0565b5b61238d86828701611c3b565b935050602084015167ffffffffffffffff8111156123ae576123ad6111d0565b5b6123ba86828701611c3b565b925050604084015167ffffffffffffffff8111156123db576123da6111d0565b5b6123e786828701611c3b565b9150509250925092565b600060a082019050612406600083018a61197f565b612413602083018961197f565b6124206040830188611dfd565b8181036060830152612433818688612182565b90508181036080830152612448818486612182565b905098975050505050505050565b7f56657374696e6743616c6c65723a20636f6e7665727420746f20636c6177626160008201527f636b2076657374696e67206163636f756e74206661696c656400000000000000602082015250565b60006124b2603983611d21565b91506124bd82612456565b604082019050919050565b600060208201905081810360008301526124e1816124a5565b9050919050565b6124f181611533565b82525050565b600060608201905061250c600083018661197f565b612519602083018561197f565b61252660408301846124e8565b949350505050565b7f56657374696e6743616c6c65723a2063726561746520636c61776261636b207660008201527f657374696e67206163636f756e7420666f7220636f6e7472616374206661696c60208201527f6564000000000000000000000000000000000000000000000000000000000000604082015250565b60006125b0604283611d21565b91506125bb8261252e565b606082019050919050565b600060208201905081810360008301526125df816125a3565b9050919050565b7f7265766572742068657265000000000000000000000000000000000000000000600082015250565b600061261c600b83611d21565b9150612627826125e6565b602082019050919050565b6000602082019050818103600083015261264b8161260f565b9050919050565b7f56657374696e6743616c6c65723a207570646174652076657374696e6720667560008201527f6e646572206661696c6564000000000000000000000000000000000000000000602082015250565b60006126ae602b83611d21565b91506126b982612652565b604082019050919050565b600060208201905081810360008301526126dd816126a1565b9050919050565b7f4661696c656420746f2073656e6420457468657220746f2064656c656761746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000612740602183611d21565b915061274b826126e4565b604082019050919050565b6000602082019050818103600083015261276f81612733565b905091905056fea26469706673582212204b37cada22f7b3efcbd3cfcf736d8690d85031d8077a13c463c51a43f0b3f3cf64736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636c49d3031161008c5780638e292e40116100665780638e292e40146101fe5780639cfef1291461022e578063cdb501751461024a578063fc9c1a8714610266576100cf565b80636c49d303146101a857806372e7c9ab146101c45780637caef81b146101f4576100cf565b806303f4be50146100d45780631e9178bb1461010457806327e235e3146101205780634fe1a8df146101525780635a2110641461016e57806361bc221a1461018a575b600080fd5b6100ee60048036038101906100e99190611233565b610296565b6040516100fb919061142e565b60405180910390f35b61011e6004803603810190610119919061156b565b61041c565b005b61013a60048036038101906101359190611662565b61068f565b6040516101499392919061168f565b60405180910390f35b61016c600480360381019061016791906116db565b610722565b005b61018860048036038101906101839190611662565b610828565b005b6101926108ee565b60405161019f91906117a6565b60405180910390f35b6101c260048036038101906101bd91906116db565b6108f4565b005b6101de60048036038101906101d99190611233565b610ac0565b6040516101eb919061142e565b60405180910390f35b6101fc610b80565b005b610218600480360381019061021391906117c1565b610c4a565b604051610225919061142e565b60405180910390f35b61024860048036038101906102439190611233565b610d94565b005b610264600480360381019061025f9190611828565b610e60565b005b610280600480360381019061027b919061187b565b610f2c565b60405161028d919061142e565b60405180910390f35b606060008290508073ffffffffffffffffffffffffffffffffffffffff16634f2be91f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156102e557600080fd5b505af11580156102f9573d6000803e3d6000fd5b5050505060008081548092919061030f90611937565b919050555061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8686866040518463ffffffff1660e01b81526004016103539392919061198e565b6000604051808303816000875af1158015610372573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061039b9190611c69565b91508073ffffffffffffffffffffffffffffffffffffffff16636deebae36040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156103e557600080fd5b505af11580156103f9573d6000803e3d6000fd5b5050505060008081548092919061040f90611cb2565b9190505550509392505050565b81156104e85760008081548092919061043490611937565b919050555060008873ffffffffffffffffffffffffffffffffffffffff16600f60405161046090611d0c565b60006040518083038185875af1925050503d806000811461049d576040519150601f19603f3d011682016040523d82523d6000602084013e6104a2565b606091505b50509050806104e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104dd90611d7e565b60405180910390fd5b505b600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df8c8c8b8b8b8b8b6040518863ffffffff1660e01b815260040161053197969594939291906121f6565b6020604051808303816000875af1158015610550573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105749190612270565b9050806105b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ad9061230f565b60405180910390fd5b81156106825760008973ffffffffffffffffffffffffffffffffffffffff16600f6040516105e390611d0c565b60006040518083038185875af1925050503d8060008114610620576040519150601f19603f3d011682016040523d82523d6000602084013e610625565b606091505b5050905080610669576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066090611d7e565b60405180910390fd5b60008081548092919061067b90611937565b9190505550505b5050505050505050505050565b606080606061080373ffffffffffffffffffffffffffffffffffffffff166327e235e3856040518263ffffffff1660e01b81526004016106cf919061232f565b600060405180830381865afa1580156106ec573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610715919061234a565b9250925092509193909250565b60008081548092919061073490611937565b9190505550600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df898989898989896040518863ffffffff1660e01b815260040161078297969594939291906123f1565b6020604051808303816000875af11580156107a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c59190612270565b905080610807576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107fe9061230f565b60405180910390fd5b60008081548092919061081990611cb2565b91905055505050505050505050565b600061080373ffffffffffffffffffffffffffffffffffffffff16635a211064836040518263ffffffff1660e01b8152600401610865919061232f565b6020604051808303816000875af1158015610884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a89190612270565b9050806108ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906124c8565b60405180910390fd5b5050565b60005481565b60008790508073ffffffffffffffffffffffffffffffffffffffff16634f2be91f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561094157600080fd5b505af1158015610955573d6000803e3d6000fd5b5050505060008081548092919061096b90611937565b9190505550600061080373ffffffffffffffffffffffffffffffffffffffff16634fe1a8df8a8a8a8a8a8a8a6040518863ffffffff1660e01b81526004016109b997969594939291906123f1565b6020604051808303816000875af11580156109d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fc9190612270565b905080610a3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a359061230f565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16636deebae36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610a8657600080fd5b505af1158015610a9a573d6000803e3d6000fd5b50505050600080815480929190610ab090611cb2565b9190505550505050505050505050565b6060600080815480929190610ad490611937565b919050555061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8585856040518463ffffffff1660e01b8152600401610b189392919061198e565b6000604051808303816000875af1158015610b37573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b609190611c69565b9050600080815480929190610b7490611cb2565b91905055509392505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb50175333060006040518463ffffffff1660e01b8152600401610bc2939291906124f7565b6020604051808303816000875af1158015610be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c059190612270565b905080610c47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3e906125c6565b60405180910390fd5b50565b6060600080815480929190610c5e90611937565b919050555061080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8686866040518463ffffffff1660e01b8152600401610ca29392919061198e565b6000604051808303816000875af1158015610cc1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610cea9190611c69565b90508115610d34576000610d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2a90612632565b60405180910390fd5b5b600080815480929190610d4690611cb2565b91905055506000610d8c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8390612632565b60405180910390fd5b949350505050565b600061080373ffffffffffffffffffffffffffffffffffffffff16639cfef1298585856040518463ffffffff1660e01b8152600401610dd59392919061198e565b6020604051808303816000875af1158015610df4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e189190612270565b905080610e5a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e51906126c4565b60405180910390fd5b50505050565b600061080373ffffffffffffffffffffffffffffffffffffffff1663cdb501758585856040518463ffffffff1660e01b8152600401610ea1939291906124f7565b6020604051808303816000875af1158015610ec0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee49190612270565b905080610f26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1d9061230f565b60405180910390fd5b50505050565b6060821561102e57600080815480929190610f4690611937565b91905055503073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161461102d5760008473ffffffffffffffffffffffffffffffffffffffff16600f604051610fa590611d0c565b60006040518083038185875af1925050503d8060008114610fe2576040519150601f19603f3d011682016040523d82523d6000602084013e610fe7565b606091505b505090508061102b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102290612756565b60405180910390fd5b505b5b61080373ffffffffffffffffffffffffffffffffffffffff166372e7c9ab8888886040518463ffffffff1660e01b815260040161106d9392919061198e565b6000604051808303816000875af115801561108c573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906110b59190611c69565b905081156111b7576000808154809291906110cf90611937565b91905055503073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16146111b65760008473ffffffffffffffffffffffffffffffffffffffff16600f60405161112e90611d0c565b60006040518083038185875af1925050503d806000811461116b576040519150601f19603f3d011682016040523d82523d6000602084013e611170565b606091505b50509050806111b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111ab90612756565b60405180910390fd5b505b5b9695505050505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611200826111d5565b9050919050565b611210816111f5565b811461121b57600080fd5b50565b60008135905061122d81611207565b92915050565b60008060006060848603121561124c5761124b6111cb565b5b600061125a8682870161121e565b935050602061126b8682870161121e565b925050604061127c8682870161121e565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156112ec5780820151818401526020810190506112d1565b60008484015250505050565b6000601f19601f8301169050919050565b6000611314826112b2565b61131e81856112bd565b935061132e8185602086016112ce565b611337816112f8565b840191505092915050565b6000819050919050565b61135581611342565b82525050565b600060408301600083015184820360008601526113788282611309565b915050602083015161138d602086018261134c565b508091505092915050565b60006113a4838361135b565b905092915050565b6000602082019050919050565b60006113c482611286565b6113ce8185611291565b9350836020820285016113e0856112a2565b8060005b8581101561141c57848403895281516113fd8582611398565b9450611408836113ac565b925060208a019950506001810190506113e4565b50829750879550505050505092915050565b6000602082019050818103600083015261144881846113b9565b905092915050565b600061145b826111d5565b9050919050565b61146b81611450565b811461147657600080fd5b50565b60008135905061148881611462565b92915050565b600067ffffffffffffffff82169050919050565b6114ab8161148e565b81146114b657600080fd5b50565b6000813590506114c8816114a2565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126114f3576114f26114ce565b5b8235905067ffffffffffffffff8111156115105761150f6114d3565b5b60208301915083602082028301111561152c5761152b6114d8565b5b9250929050565b60008115159050919050565b61154881611533565b811461155357600080fd5b50565b6000813590506115658161153f565b92915050565b6000806000806000806000806000806101008b8d03121561158f5761158e6111cb565b5b600061159d8d828e01611479565b9a505060206115ae8d828e0161121e565b99505060406115bf8d828e01611479565b98505060606115d08d828e016114b9565b97505060808b013567ffffffffffffffff8111156115f1576115f06111d0565b5b6115fd8d828e016114dd565b965096505060a08b013567ffffffffffffffff8111156116205761161f6111d0565b5b61162c8d828e016114dd565b945094505060c061163f8d828e01611556565b92505060e06116508d828e01611556565b9150509295989b9194979a5092959850565b600060208284031215611678576116776111cb565b5b60006116868482850161121e565b91505092915050565b600060608201905081810360008301526116a981866113b9565b905081810360208301526116bd81856113b9565b905081810360408301526116d181846113b9565b9050949350505050565b600080600080600080600060a0888a0312156116fa576116f96111cb565b5b60006117088a828b0161121e565b97505060206117198a828b0161121e565b965050604061172a8a828b016114b9565b955050606088013567ffffffffffffffff81111561174b5761174a6111d0565b5b6117578a828b016114dd565b9450945050608088013567ffffffffffffffff81111561177a576117796111d0565b5b6117868a828b016114dd565b925092505092959891949750929550565b6117a081611342565b82525050565b60006020820190506117bb6000830184611797565b92915050565b600080600080608085870312156117db576117da6111cb565b5b60006117e98782880161121e565b94505060206117fa8782880161121e565b935050604061180b8782880161121e565b925050606061181c87828801611556565b91505092959194509250565b600080600060608486031215611841576118406111cb565b5b600061184f8682870161121e565b93505060206118608682870161121e565b925050604061187186828701611556565b9150509250925092565b60008060008060008060c087890312156118985761189761 ... [truncated]
precompiles/vesting/testdata/VestingCaller.sol+204 −17 modified@@ -3,12 +3,15 @@ pragma solidity ^0.8.17; import "../../common/Types.sol"; import "../VestingI.sol" as vesting; +import "../../testutil/contracts/ICounter.sol"; /// @title VestingCaller /// @author Evmos Core Team /// @dev This contract is used to test external contract calls to the vesting precompile. contract VestingCaller { - + /// counter is used to test the state persistence bug, when EVM and Cosmos state were both + /// changed in the same function. + uint256 public counter; /// @dev Defines a method to test creating a new clawback vesting account. /// @param funder The address of the account that will fund the vesting account. /// @param to The address of the account that will receive the vesting account. @@ -23,7 +26,10 @@ contract VestingCaller { to, enableGovClawback ); - require(success, "VestingCaller: create clawback vesting account failed"); + require( + success, + "VestingCaller: create clawback vesting account failed" + ); } /// @dev Defines a method to test funding a vesting account @@ -39,14 +45,96 @@ contract VestingCaller { vesting.Period[] calldata lockupPeriods, vesting.Period[] calldata vestingPeriods ) public { + counter++; + bool success = vesting.VESTING_CONTRACT.fundVestingAccount( + funder, + to, + startTime, + lockupPeriods, + vestingPeriods + ); + require( + success, + "VestingCaller: create clawback vesting account failed" + ); + counter--; + } + + /// @dev Defines a method to test funding a vesting account. + /// If specified, it sends 15 aevmos to the funder before and/or after + /// the precompile call + /// @param funder The address of the account that will fund the vesting account. + /// @param to The address of the account that will receive the vesting account. + /// @param _transferTo The address to send some funds to. + /// @param startTime The time at which the vesting account will start. + /// @param lockupPeriods The lockup periods of the vesting account. + /// @param vestingPeriods The vesting periods of the vesting account. + /// @param transferBefore A boolean to specify if the contract should transfer + /// funds to the funder before the precompile call. + /// @param transferAfter A boolean to specify if the contract should transfer + /// funds to the funder after the precompile call. + function fundVestingAccountAndTransfer( + address payable funder, + address to, + address payable _transferTo, + uint64 startTime, + vesting.Period[] calldata lockupPeriods, + vesting.Period[] calldata vestingPeriods, + bool transferBefore, + bool transferAfter + ) public { + if (transferBefore) { + counter++; + (bool sent, ) = _transferTo.call{value: 15}(""); + require(sent, "Failed to send Ether to funder"); + } bool success = vesting.VESTING_CONTRACT.fundVestingAccount( funder, to, startTime, lockupPeriods, vestingPeriods ); - require(success, "VestingCaller: create clawback vesting account failed"); + require( + success, + "VestingCaller: create clawback vesting account failed" + ); + if (transferAfter) { + (bool sent, ) = _transferTo.call{value: 15}(""); + require(sent, "Failed to send Ether to funder"); + counter++; + } + } + + /// @dev Defines a method to test funding a vesting account + /// @param funder The address of the Counter contract that will fund the vesting account. + /// @param to The address of the account that will receive the vesting account. + /// @param startTime The time at which the vesting account will start. + /// @param lockupPeriods The lockup periods of the vesting account. + /// @param vestingPeriods The vesting periods of the vesting account. + function fundVestingAccountWithCounterContract( + address funder, + address to, + uint64 startTime, + vesting.Period[] calldata lockupPeriods, + vesting.Period[] calldata vestingPeriods + ) public { + ICounter counterContract = ICounter(funder); + counterContract.add(); + counter++; + bool success = vesting.VESTING_CONTRACT.fundVestingAccount( + funder, + to, + startTime, + lockupPeriods, + vestingPeriods + ); + require( + success, + "VestingCaller: create clawback vesting account failed" + ); + counterContract.subtract(); + counter--; } /// @dev Defines a method to test clawing back coins from a vesting account. @@ -59,7 +147,86 @@ contract VestingCaller { address account, address dest ) public returns (Coin[] memory coins) { - return vesting.VESTING_CONTRACT.clawback(funder, account, dest); + counter++; + coins = vesting.VESTING_CONTRACT.clawback(funder, account, dest); + counter--; + return coins; + } + + /// @dev Defines a method to test clawing back coins from a vesting account. + /// @param funder The address of the account that funded the vesting account. + /// @param account The address of the vesting account. + /// @param dest The address of the account that will receive the clawed back coins. + /// @param _transferTo The address to send some funds to. + /// @param _before Boolean to specify if funds should be transferred to _transferTo before the precompile call + /// @param _after Boolean to specify if funds should be transferred to _transferTo after the precompile call + /// @return coins The coins that were clawed back from the vesting account. + function clawbackWithTransfer( + address funder, + address account, + address dest, + address payable _transferTo, + bool _before, + bool _after + ) public returns (Coin[] memory coins) { + if (_before) { + counter++; + if (dest != address(this)) { + (bool sent, ) = _transferTo.call{value: 15}(""); + require(sent, "Failed to send Ether to delegator"); + } + } + coins = vesting.VESTING_CONTRACT.clawback(funder, account, dest); + if (_after) { + counter++; + if (dest != address(this)) { + (bool sent, ) = _transferTo.call{value: 15}(""); + require(sent, "Failed to send Ether to delegator"); + } + } + return coins; + } + + /// @dev Defines a method to test clawing back coins from a vesting account. + /// It is used for testing the state revert. + /// @param funder The address of the account that funded the vesting account. + /// @param account The address of the vesting account. + /// @param dest The address of the account that will receive the clawed back coins. + /// @param before Boolean to specify if should revert before counter change. + /// @return coins The coins that were clawed back from the vesting account. + function clawbackWithRevert( + address funder, + address account, + address dest, + bool before + ) public returns (Coin[] memory coins) { + counter++; + coins = vesting.VESTING_CONTRACT.clawback(funder, account, dest); + if (before) { + require(false, "revert here"); + } + counter--; + require(false, "revert here"); + return coins; + } + + /// @dev Defines a method to test clawing back coins from a vesting account. + /// @param funder The address of the account that funded the vesting account. + /// @param account The address of the vesting account. + /// @param dest The address of the Counter smart contract that will receive the clawed back coins. + /// @return coins The coins that were clawed back from the vesting account. + function clawbackWithCounterCall( + address funder, + address account, + address dest + ) public returns (Coin[] memory coins) { + ICounter counterContract = ICounter(dest); + counterContract.add(); + counter++; + coins = vesting.VESTING_CONTRACT.clawback(funder, account, dest); + counterContract.subtract(); + counter--; + return coins; } /// @dev Defines a method to test updating the funder of a vesting account. @@ -71,32 +238,52 @@ contract VestingCaller { address newFunder, address vestingAddr ) public { - bool success = vesting.VESTING_CONTRACT.updateVestingFunder(funder, newFunder, vestingAddr); + bool success = vesting.VESTING_CONTRACT.updateVestingFunder( + funder, + newFunder, + vestingAddr + ); require(success, "VestingCaller: update vesting funder failed"); } /// @dev Defines a method to test converting a vesting account to a clawback vesting account. /// @param vestingAddr The address of the vesting account. - function convertVestingAccount( - address vestingAddr - ) public { - bool success = vesting.VESTING_CONTRACT.convertVestingAccount(vestingAddr); - require(success, "VestingCaller: convert to clawback vesting account failed"); + function convertVestingAccount(address vestingAddr) public { + bool success = vesting.VESTING_CONTRACT.convertVestingAccount( + vestingAddr + ); + require( + success, + "VestingCaller: convert to clawback vesting account failed" + ); } /// @dev Converts a smart contract address to a vesting account on top of it being a smart contract function createClawbackVestingAccountForContract() public { - bool success = vesting.VESTING_CONTRACT.createClawbackVestingAccount(msg.sender, address(this), false); - require(success, "VestingCaller: create clawback vesting account for contract failed"); + bool success = vesting.VESTING_CONTRACT.createClawbackVestingAccount( + msg.sender, + address(this), + false + ); + require( + success, + "VestingCaller: create clawback vesting account for contract failed" + ); } /// @dev Defines a method to test getting the balances of a vesting account. /// @param vestingAddr The address of the vesting account. - function balances(address vestingAddr) public view returns ( - Coin[] memory locked, - Coin[] memory unvested, - Coin[] memory vested - ) { + function balances( + address vestingAddr + ) + public + view + returns ( + Coin[] memory locked, + Coin[] memory unvested, + Coin[] memory vested + ) + { return vesting.VESTING_CONTRACT.balances(vestingAddr); } }
precompiles/vesting/tx.go+75 −21 modified@@ -6,10 +6,14 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/evmos/evmos/v18/precompiles/authorization" + cmn "github.com/evmos/evmos/v18/precompiles/common" + "github.com/evmos/evmos/v18/utils" ) const ( @@ -27,7 +31,7 @@ const ( ) // CreateClawbackVestingAccount creates a new clawback vesting account -func (p Precompile) CreateClawbackVestingAccount( +func (p *Precompile) CreateClawbackVestingAccount( ctx sdk.Context, origin common.Address, stateDB vm.StateDB, @@ -39,6 +43,7 @@ func (p Precompile) CreateClawbackVestingAccount( return nil, err } + // Only EOA can be vesting accounts // Check if the origin matches the vesting address if origin != vestingAddr { return nil, fmt.Errorf(ErrDifferentFromOrigin, origin, vestingAddr) @@ -63,7 +68,7 @@ func (p Precompile) CreateClawbackVestingAccount( } // FundVestingAccount funds a vesting account by creating vesting schedules -func (p Precompile) FundVestingAccount( +func (p *Precompile) FundVestingAccount( ctx sdk.Context, contract *vm.Contract, origin common.Address, @@ -76,8 +81,12 @@ func (p Precompile) FundVestingAccount( return nil, err } - // if caller address is origin, the funder MUST match the origin - if contract.CallerAddress == origin && origin != funderAddr { + isContractCaller := contract.CallerAddress != origin + + // funder can only be the origin or the contract.Caller + isContractFunder := contract.CallerAddress == funderAddr && isContractCaller + + if !isContractFunder && origin != funderAddr { return nil, fmt.Errorf(ErrDifferentFromOrigin, origin, funderAddr) } @@ -90,11 +99,15 @@ func (p Precompile) FundVestingAccount( ), ) - if contract.CallerAddress != origin { - // check if authorization exists - _, _, err := authorization.CheckAuthzExists(ctx, p.AuthzKeeper, contract.CallerAddress, origin, FundVestingAccountMsgURL) + // in case the contract is the funder + // don't check for auth. + // The smart contract (funder) should handle who is authorized to make this call + if isContractCaller && !isContractFunder { + // if calling from a contract and the contract is not the funder (origin == funderAddr) + // check that an authorization exists + _, _, err := authorization.CheckAuthzExists(ctx, p.AuthzKeeper, contract.CallerAddress, funderAddr, FundVestingAccountMsgURL) if err != nil { - return nil, fmt.Errorf(authorization.ErrAuthzDoesNotExistOrExpired, contract.CallerAddress, origin) + return nil, fmt.Errorf(authorization.ErrAuthzDoesNotExistOrExpired, FundVestingAccountMsgURL, contract.CallerAddress) } } @@ -103,6 +116,21 @@ func (p Precompile) FundVestingAccount( return nil, err } + if isContractCaller { + vestingCoins := msg.VestingPeriods.TotalAmount() + lockedUpCoins := msg.LockupPeriods.TotalAmount() + if vestingCoins.IsZero() && lockedUpCoins.IsAllPositive() { + vestingCoins = lockedUpCoins + } + + // NOTE: This ensures that the changes in the bank keeper are correctly mirrored to the EVM stateDB. + amt := vestingCoins.AmountOf(utils.BaseDenom).BigInt() + p.SetBalanceChangeEntries( + cmn.NewBalanceChangeEntry(funderAddr, amt, cmn.Sub), + cmn.NewBalanceChangeEntry(vestingAddr, amt, cmn.Add), + ) + } + if err = p.EmitFundVestingAccountEvent(ctx, stateDB, msg, funderAddr, vestingAddr, lockupPeriods, vestingPeriods); err != nil { return nil, err } @@ -111,7 +139,7 @@ func (p Precompile) FundVestingAccount( } // Clawback clawbacks tokens from a clawback vesting account -func (p Precompile) Clawback( +func (p *Precompile) Clawback( ctx sdk.Context, contract *vm.Contract, origin common.Address, @@ -124,8 +152,13 @@ func (p Precompile) Clawback( return nil, err } + isContractCaller := contract.CallerAddress != origin + + // funder can only be the origin or the contract.Caller + isContractFunder := contract.CallerAddress == funderAddr && isContractCaller + // if caller address is origin, the funder MUST match the origin - if contract.CallerAddress == origin && origin != funderAddr { + if !isContractFunder && origin != funderAddr { return nil, fmt.Errorf(ErrDifferentFunderOrigin, origin, funderAddr) } @@ -138,11 +171,15 @@ func (p Precompile) Clawback( ), ) - if contract.CallerAddress != origin { - // check if authorization exists - _, _, err := authorization.CheckAuthzExists(ctx, p.AuthzKeeper, contract.CallerAddress, origin, ClawbackMsgURL) + // in case the contract is the funder + // don't check for auth. + // The smart contract (funder) should handle who is authorized to make this call + if isContractCaller && !isContractFunder { + // if calling from a contract and the contract is not the funder (origin == funderAddr) + // check that an authorization exists. + _, _, err := authorization.CheckAuthzExists(ctx, p.AuthzKeeper, contract.CallerAddress, funderAddr, ClawbackMsgURL) if err != nil { - return nil, fmt.Errorf(authorization.ErrAuthzDoesNotExistOrExpired, contract.CallerAddress, origin) + return nil, fmt.Errorf(authorization.ErrAuthzDoesNotExistOrExpired, ClawbackMsgURL, contract.CallerAddress) } } @@ -151,6 +188,16 @@ func (p Precompile) Clawback( return nil, err } + if isContractCaller { + // NOTE: This ensures that the changes in the bank keeper are correctly mirrored to the EVM stateDB when calling + // the precompile from another contract. + clawbackAmt := response.Coins.AmountOf(utils.BaseDenom).BigInt() + p.SetBalanceChangeEntries( + cmn.NewBalanceChangeEntry(accountAddr, clawbackAmt, cmn.Sub), + cmn.NewBalanceChangeEntry(destAddr, clawbackAmt, cmn.Add), + ) + } + if err = p.EmitClawbackEvent(ctx, stateDB, funderAddr, accountAddr, destAddr); err != nil { return nil, err } @@ -161,7 +208,7 @@ func (p Precompile) Clawback( } // UpdateVestingFunder updates the vesting funder of a clawback vesting account -func (p Precompile) UpdateVestingFunder( +func (p *Precompile) UpdateVestingFunder( ctx sdk.Context, contract *vm.Contract, origin common.Address, @@ -174,8 +221,11 @@ func (p Precompile) UpdateVestingFunder( return nil, err } + isContractCall := contract.CallerAddress != origin + isContractFunder := contract.CallerAddress == funderAddr && isContractCall + // only the funder can update the funder // if caller address is origin, the funder MUST match the origin - if contract.CallerAddress == origin && origin != funderAddr { + if !isContractFunder && origin != funderAddr { return nil, fmt.Errorf(ErrDifferentFunderOrigin, origin, funderAddr) } @@ -188,11 +238,15 @@ func (p Precompile) UpdateVestingFunder( ), ) - if contract.CallerAddress != origin { - // check if authorization exists - _, _, err := authorization.CheckAuthzExists(ctx, p.AuthzKeeper, contract.CallerAddress, origin, UpdateVestingFunderMsgURL) + // in case the contract is the funder + // don't check for auth. + // The smart contract (funder) should handle who is authorized to make this call + if isContractCall && !isContractFunder { + // if calling from a contract and the contract is not the funder (origin == funderAddr) + // check that an authorization exists + _, _, err := authorization.CheckAuthzExists(ctx, p.AuthzKeeper, contract.CallerAddress, funderAddr, UpdateVestingFunderMsgURL) if err != nil { - return nil, fmt.Errorf(authorization.ErrAuthzDoesNotExistOrExpired, contract.CallerAddress, origin) + return nil, fmt.Errorf(authorization.ErrAuthzDoesNotExistOrExpired, UpdateVestingFunderMsgURL, contract.CallerAddress) } } @@ -209,7 +263,7 @@ func (p Precompile) UpdateVestingFunder( } // ConvertVestingAccount converts a clawback vesting account to a base account once the vesting period is over. -func (p Precompile) ConvertVestingAccount( +func (p *Precompile) ConvertVestingAccount( ctx sdk.Context, stateDB vm.StateDB, method *abi.Method,
precompiles/vesting/utils_test.go+23 −2 modified@@ -18,6 +18,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" evmosapp "github.com/evmos/evmos/v18/app" @@ -236,8 +237,8 @@ func (s *PrecompileTestSuite) BuildCallArgs( func (s *PrecompileTestSuite) FundTestClawbackVestingAccount() { method := s.precompile.Methods[vesting.FundVestingAccountMethod] createArgs := []interface{}{s.address, toAddr, uint64(time.Now().Unix()), lockupPeriods, vestingPeriods} - //nolint msg, _, _, _, _, err := vesting.NewMsgFundVestingAccount(createArgs, &method) + s.Require().NoError(err) _, err = s.app.VestingKeeper.FundVestingAccount(s.ctx, msg) s.Require().NoError(err) vestingAcc, err := s.app.VestingKeeper.Balances(s.ctx, &vestingtypes.QueryBalancesRequest{Address: sdk.AccAddress(toAddr.Bytes()).String()}) @@ -249,8 +250,8 @@ func (s *PrecompileTestSuite) FundTestClawbackVestingAccount() { // CreateTestClawbackVestingAccount creates a vesting account that can clawback func (s *PrecompileTestSuite) CreateTestClawbackVestingAccount(funder, vestingAddr common.Address) { msgArgs := []interface{}{funder, vestingAddr, false} - //nolint msg, _, _, err := vesting.NewMsgCreateClawbackVestingAccount(msgArgs) + s.Require().NoError(err) err = evmosutil.FundAccount(s.ctx, s.app.BankKeeper, vestingAddr.Bytes(), sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, math.NewInt(100)))) s.Require().NoError(err) _, err = s.app.VestingKeeper.CreateClawbackVestingAccount(s.ctx, msg) @@ -312,3 +313,23 @@ func (s *PrecompileTestSuite) NextBlock() { s.ctx, err = evmosutil.CommitAndCreateNewCtx(s.ctx, s.app, time.Second, nil) Expect(err).To(BeNil(), "failed to commit block") } + +// mergeEventMaps is a helper function to merge events maps from different contracts. +// If duplicates events are present, map2 override map1 values. +func mergeEventMaps(map1, map2 map[string]abi.Event) map[string]abi.Event { + // Create a new map to hold the merged result + mergedMap := make(map[string]abi.Event) + + // Copy all key-value pairs from map1 to mergedMap + for k, v := range map1 { + mergedMap[k] = v + } + + // Copy all key-value pairs from map2 to mergedMap + // If there are duplicate keys, values from map2 will overwrite those from map1 + for k, v := range map2 { + mergedMap[k] = v + } + + return mergedMap +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-q6hg-6m9x-5g9cghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-39696ghsaADVISORY
- github.com/evmos/evmos/commit/0a620e176617a835ac697eea494afea09185dfafghsax_refsource_MISCWEB
- github.com/evmos/evmos/security/advisories/GHSA-q6hg-6m9x-5g9cghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.