diff --git a/contracts/debug_precompile_caller.go b/contracts/debug_precompile_caller.go new file mode 100644 index 00000000..b211e5de --- /dev/null +++ b/contracts/debug_precompile_caller.go @@ -0,0 +1,30 @@ +package contracts + +import ( + _ "embed" + + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +var ( + //go:embed solidity/DebugPrecompileCaller.json + DebugPrecompileCallerJSON []byte + + // GreeterContract is the compiled Greeter contract + DebugPrecompileCallerContract evmtypes.CompiledContract +) + +func init() { + var err error + if DebugPrecompileCallerContract, err = contractutils.ConvertHardhatBytesToCompiledContract( + DebugPrecompileCallerJSON, + ); err != nil { + panic(err) + } +} + +// LoadGreeter loads the Greeter contract +func LoadDebugPrecompileCaller() (evmtypes.CompiledContract, error) { + return DebugPrecompileCallerContract, nil +} diff --git a/contracts/erc20_recursive_non_reverting.go b/contracts/erc20_recursive_non_reverting.go new file mode 100644 index 00000000..0d5d8af3 --- /dev/null +++ b/contracts/erc20_recursive_non_reverting.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadERC20RecursiveNonReverting() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/ERC20RecursiveNonRevertingPrecompileCall.json") +} diff --git a/contracts/erc20_recursive_reverting.go b/contracts/erc20_recursive_reverting.go new file mode 100644 index 00000000..403d0287 --- /dev/null +++ b/contracts/erc20_recursive_reverting.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadERC20RecursiveReverting() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/ERC20RecursiveRevertingPrecompileCall.json") +} diff --git a/contracts/solidity/DebugPrecompileCaller.json b/contracts/solidity/DebugPrecompileCaller.json new file mode 100644 index 00000000..cca7100b --- /dev/null +++ b/contracts/solidity/DebugPrecompileCaller.json @@ -0,0 +1,35 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "DebugPrecompileCaller", + "sourceName": "solidity/DebugPrecompileCaller.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "CallFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "counter", + "type": "uint256" + } + ], + "name": "callback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608080604052346100165761023e908161001c8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c63ff585caf1461002857600080fd5b34610047576020366003190112610047576100446004356100f4565b80f35b80fd5b3d156100a65767ffffffffffffffff903d8281116100905760405192601f8201601f19908116603f01168401908111848210176100905760405282523d6000602084013e565b634e487b7160e01b600052604160045260246000fd5b606090565b6020808252825181830181905290939260005b8281106100e057505060409293506000838284010152601f8019910116010190565b8181018601518482016040015285016100be565b60005b81811061017a5750600381116101775760405190602082019060008252602183015260218252606082019082821067ffffffffffffffff8311176100905760009283926040525190826107995af161014d61004a565b90156101565750565b60405163a5fa8d2b60e01b815290819061017390600483016100ab565b0390fd5b50565b60408051600160f81b60208201908152600182528183019067ffffffffffffffff82118383101761009057600092839285525190826107995af1906101bd61004a565b91156101ec57505060001981146101d6576001016100f7565b634e487b7160e01b600052601160045260246000fd5b5163a5fa8d2b60e01b81529150819061017390600483016100ab56fea2646970667358221220f0ddd005e729c0bf54b8295a483a2d7c84c3948a24b42ea5b8f906cf9b1c361f64736f6c63430008140033", + "deployedBytecode": "0x6080604052600436101561001257600080fd5b6000803560e01c63ff585caf1461002857600080fd5b34610047576020366003190112610047576100446004356100f4565b80f35b80fd5b3d156100a65767ffffffffffffffff903d8281116100905760405192601f8201601f19908116603f01168401908111848210176100905760405282523d6000602084013e565b634e487b7160e01b600052604160045260246000fd5b606090565b6020808252825181830181905290939260005b8281106100e057505060409293506000838284010152601f8019910116010190565b8181018601518482016040015285016100be565b60005b81811061017a5750600381116101775760405190602082019060008252602183015260218252606082019082821067ffffffffffffffff8311176100905760009283926040525190826107995af161014d61004a565b90156101565750565b60405163a5fa8d2b60e01b815290819061017390600483016100ab565b0390fd5b50565b60408051600160f81b60208201908152600182528183019067ffffffffffffffff82118383101761009057600092839285525190826107995af1906101bd61004a565b91156101ec57505060001981146101d6576001016100f7565b634e487b7160e01b600052601160045260246000fd5b5163a5fa8d2b60e01b81529150819061017390600483016100ab56fea2646970667358221220f0ddd005e729c0bf54b8295a483a2d7c84c3948a24b42ea5b8f906cf9b1c361f64736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/DebugPrecompileCaller.sol b/contracts/solidity/DebugPrecompileCaller.sol new file mode 100644 index 00000000..819e7a74 --- /dev/null +++ b/contracts/solidity/DebugPrecompileCaller.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.4; + +contract DebugPrecompileCaller { + address constant debugPrecompile = 0x0000000000000000000000000000000000000799; + error CallFailed(bytes data); + function callback(uint256 counter) public { + bool result; + bytes memory data; + + // emit events + for (uint i = 0; i < counter; i++) { + (result, data) = debugPrecompile.call(abi.encodePacked(uint8(1))); + if (!result) { + revert CallFailed(data); + } + } + + if (counter > 3) { + // stop the recursion + return; + } + + // recursive call + (result, data) = debugPrecompile.call(abi.encodePacked(uint8(0), counter)); + if (!result) { + revert CallFailed(data); + } + } +} diff --git a/contracts/solidity/ERC20RecursiveNonRevertingPrecompileCall.json b/contracts/solidity/ERC20RecursiveNonRevertingPrecompileCall.json new file mode 100644 index 00000000..6e660def --- /dev/null +++ b/contracts/solidity/ERC20RecursiveNonRevertingPrecompileCall.json @@ -0,0 +1,758 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20RecursiveNonRevertingPrecompileCall", + "sourceName": "solidity/ERC20RecursiveNonRevertingPrecompileCall.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "BeforeTokenTransferHookCalled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "BURNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnCoins", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "validatorAddress", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getRoleMember", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleMemberCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b50604051620041d1380380620041d18339818101604052810190620000379190620005e0565b828281600590816200004a9190620008c5565b5080600690816200005c9190620008c5565b5050506000600760006101000a81548160ff0219169083151502179055506200009e6000801b620000926200017b60201b60201c565b6200018360201b60201c565b620000df7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6620000d36200017b60201b60201c565b6200018360201b60201c565b620001207f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a620001146200017b60201b60201c565b6200018360201b60201c565b620001617f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848620001556200017b60201b60201c565b6200018360201b60201c565b6200017281620001c160201b60201c565b505050620009ac565b600033905090565b620001958282620001df60201b60201c565b620001bc8160016000858152602001908152602001600020620002d060201b90919060201c565b505050565b80600760016101000a81548160ff021916908360ff16021790555050565b620001f182826200030860201b60201c565b620002cc57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620002716200017b60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600062000300836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6200037260201b60201c565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000620003868383620003ec60201b60201c565b620003e1578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050620003e6565b600090505b92915050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000478826200042d565b810181811067ffffffffffffffff821117156200049a57620004996200043e565b5b80604052505050565b6000620004af6200040f565b9050620004bd82826200046d565b919050565b600067ffffffffffffffff821115620004e057620004df6200043e565b5b620004eb826200042d565b9050602081019050919050565b60005b8381101562000518578082015181840152602081019050620004fb565b60008484015250505050565b60006200053b6200053584620004c2565b620004a3565b9050828152602081018484840111156200055a576200055962000428565b5b62000567848285620004f8565b509392505050565b600082601f83011262000587576200058662000423565b5b81516200059984826020860162000524565b91505092915050565b600060ff82169050919050565b620005ba81620005a2565b8114620005c657600080fd5b50565b600081519050620005da81620005af565b92915050565b600080600060608486031215620005fc57620005fb62000419565b5b600084015167ffffffffffffffff8111156200061d576200061c6200041e565b5b6200062b868287016200056f565b935050602084015167ffffffffffffffff8111156200064f576200064e6200041e565b5b6200065d868287016200056f565b92505060406200067086828701620005c9565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006cd57607f821691505b602082108103620006e357620006e262000685565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200074d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200070e565b6200075986836200070e565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620007a6620007a06200079a8462000771565b6200077b565b62000771565b9050919050565b6000819050919050565b620007c28362000785565b620007da620007d182620007ad565b8484546200071b565b825550505050565b600090565b620007f1620007e2565b620007fe818484620007b7565b505050565b5b8181101562000826576200081a600082620007e7565b60018101905062000804565b5050565b601f82111562000875576200083f81620006e9565b6200084a84620006fe565b810160208510156200085a578190505b620008726200086985620006fe565b83018262000803565b50505b505050565b600082821c905092915050565b60006200089a600019846008026200087a565b1980831691505092915050565b6000620008b5838362000887565b9150826002028217905092915050565b620008d0826200067a565b67ffffffffffffffff811115620008ec57620008eb6200043e565b5b620008f88254620006b4565b620009058282856200082a565b600060209050601f8311600181146200093d576000841562000928578287015190505b620009348582620008a7565b865550620009a4565b601f1984166200094d86620006e9565b60005b82811015620009775784890151825560018201915060208501945060208101905062000950565b8683101562000997578489015162000993601f89168262000887565b8355505b6001600288020188555050505b505050505050565b61381580620009bc6000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806342966c681161010f578063a217fddf116100a2578063d539139311610071578063d5391393146105b9578063d547741f146105d7578063dd62ed3e146105f3578063e63ab1e914610623576101f0565b8063a217fddf1461050b578063a457c2d714610529578063a9059cbb14610559578063ca15c87314610589576101f0565b80638456cb59116100de5780638456cb59146104835780639010d07c1461048d57806391d14854146104bd57806395d89b41146104ed576101f0565b806342966c68146103fd5780635c975abb1461041957806370a082311461043757806379cc679014610467576101f0565b8063282c51f311610187578063372500ab11610156578063372500ab1461039d57806339509351146103a75780633f4ba83a146103d757806340c10f19146103e1576101f0565b8063282c51f3146103295780632f2ff15d14610347578063313ce5671461036357806336568abe14610381576101f0565b806318160ddd116101c357806318160ddd1461028f5780631cf2c7e2146102ad57806323b872dd146102c9578063248a9ca3146102f9576101f0565b806301ffc9a7146101f557806303f24de11461022557806306fdde0314610241578063095ea7b31461025f575b600080fd5b61020f600480360381019061020a91906122fa565b610641565b60405161021c9190612342565b60405180910390f35b61023f600480360381019061023a91906124d9565b6106bb565b005b610249610786565b60405161025691906125b4565b60405180910390f35b61027960048036038101906102749190612634565b610818565b6040516102869190612342565b60405180910390f35b61029761083b565b6040516102a49190612683565b60405180910390f35b6102c760048036038101906102c29190612634565b610845565b005b6102e360048036038101906102de919061269e565b6108c3565b6040516102f09190612342565b60405180910390f35b610313600480360381019061030e9190612727565b6108f2565b6040516103209190612763565b60405180910390f35b610331610911565b60405161033e9190612763565b60405180910390f35b610361600480360381019061035c919061277e565b610935565b005b61036b610956565b60405161037891906127da565b60405180910390f35b61039b6004803603810190610396919061277e565b61096d565b005b6103a56109f0565b005b6103c160048036038101906103bc9190612634565b610a74565b6040516103ce9190612342565b60405180910390f35b6103df610aab565b005b6103fb60048036038101906103f69190612634565b610b25565b005b610417600480360381019061041291906127f5565b610ba3565b005b610421610bb7565b60405161042e9190612342565b60405180910390f35b610451600480360381019061044c9190612822565b610bce565b60405161045e9190612683565b60405180910390f35b610481600480360381019061047c9190612634565b610c17565b005b61048b610c37565b005b6104a760048036038101906104a2919061284f565b610cb1565b6040516104b4919061289e565b60405180910390f35b6104d760048036038101906104d2919061277e565b610ce0565b6040516104e49190612342565b60405180910390f35b6104f5610d4a565b60405161050291906125b4565b60405180910390f35b610513610ddc565b6040516105209190612763565b60405180910390f35b610543600480360381019061053e9190612634565b610de3565b6040516105509190612342565b60405180910390f35b610573600480360381019061056e9190612634565b610e5a565b6040516105809190612342565b60405180910390f35b6105a3600480360381019061059e9190612727565b610e7d565b6040516105b09190612683565b60405180910390f35b6105c1610ea1565b6040516105ce9190612763565b60405180910390f35b6105f160048036038101906105ec919061277e565b610ec5565b005b61060d600480360381019061060891906128b9565b610ee6565b60405161061a9190612683565b60405180910390f35b61062b610f6d565b6040516106389190612763565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106b457506106b382610f91565b5b9050919050565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3085856040518463ffffffff1660e01b81526004016106fc939291906128f9565b6020604051808303816000875af115801561071b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073f9190612963565b905080610781576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610778906129dc565b60405180910390fd5b505050565b60606005805461079590612a2b565b80601f01602080910402602001604051908101604052809291908181526020018280546107c190612a2b565b801561080e5780601f106107e35761010080835404028352916020019161080e565b820191906000526020600020905b8154815290600101906020018083116107f157829003601f168201915b5050505050905090565b60008061082361100b565b9050610830818585611013565b600191505092915050565b6000600454905090565b6108767f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84861087161100b565b610ce0565b6108b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ac90612ace565b60405180910390fd5b6108bf82826111dc565b5050565b6000806108ce61100b565b90506108db8582856113ab565b6108e6858585611437565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b61093e826108f2565b610947816116b0565b61095183836116c4565b505050565b6000600760019054906101000a900460ff16905090565b61097561100b565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146109e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d990612b60565b60405180910390fd5b6109ec82826116f8565b5050565b61080173ffffffffffffffffffffffffffffffffffffffff16632efe8a5f3060646040518363ffffffff1660e01b8152600401610a2e929190612bd5565b6020604051808303816000875af1158015610a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a719190612963565b50565b600080610a7f61100b565b9050610aa0818585610a918589610ee6565b610a9b9190612c2d565b611013565b600191505092915050565b610adc7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610ad761100b565b610ce0565b610b1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1290612cd3565b60405180910390fd5b610b2361172c565b565b610b567f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610b5161100b565b610ce0565b610b95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8c90612d65565b60405180910390fd5b610b9f828261178f565b5050565b610bb4610bae61100b565b826111dc565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b610c2982610c2361100b565b836113ab565b610c3382826111dc565b5050565b610c687f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610c6361100b565b610ce0565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e90612df7565b60405180910390fd5b610caf6118e6565b565b6000610cd8826001600086815260200190815260200160002061194990919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610d5990612a2b565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8590612a2b565b8015610dd25780601f10610da757610100808354040283529160200191610dd2565b820191906000526020600020905b815481529060010190602001808311610db557829003601f168201915b5050505050905090565b6000801b81565b600080610dee61100b565b90506000610dfc8286610ee6565b905083811015610e41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3890612e89565b60405180910390fd5b610e4e8286868403611013565b60019250505092915050565b600080610e6561100b565b9050610e72818585611437565b600191505092915050565b6000610e9a60016000848152602001908152602001600020611963565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610ece826108f2565b610ed7816116b0565b610ee183836116f8565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611004575061100382611978565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611082576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107990612f1b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110e890612fad565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516111cf9190612683565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361124b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112429061303f565b60405180910390fd5b611257826000836119e2565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156112de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d5906130d1565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516113929190612683565b60405180910390a36113a683600084611aa7565b505050565b60006113b78484610ee6565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114315781811015611423576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141a9061313d565b60405180910390fd5b6114308484848403611013565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036114a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149d906131cf565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611515576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150c90613261565b60405180910390fd5b6115208383836119e2565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156115a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159e906132f3565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516116979190612683565b60405180910390a36116aa848484611aa7565b50505050565b6116c1816116bc61100b565b611aac565b50565b6116ce8282611b31565b6116f38160016000858152602001908152602001600020611c1190919063ffffffff16565b505050565b6117028282611c41565b6117278160016000858152602001908152602001600020611d2290919063ffffffff16565b505050565b611734611d52565b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61177861100b565b604051611785919061289e565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036117fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117f59061335f565b60405180910390fd5b61180a600083836119e2565b806004600082825461181c9190612c2d565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118ce9190612683565b60405180910390a36118e260008383611aa7565b5050565b6118ee611d9b565b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861193261100b565b60405161193f919061289e565b60405180910390a1565b60006119588360000183611de5565b60001c905092915050565b600061197182600001611e10565b9050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b7f6a7461657441bf111caa502b48bec73847d91c1265dc315d914c2d2a6c95fcfe838383604051611a159392919061337f565b60405180910390a160005b6005811015611a96573073ffffffffffffffffffffffffffffffffffffffff1663372500ab6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a7157600080fd5b505af1925050508015611a82575060015b508080611a8e906133b6565b915050611a20565b50611aa2838383611e21565b505050565b505050565b611ab68282610ce0565b611b2d57611ac381611e79565b611ad18360001c6020611ea6565b604051602001611ae29291906134d2565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2491906125b4565b60405180910390fd5b5050565b611b3b8282610ce0565b611c0d57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611bb261100b565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611c39836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6120e2565b905092915050565b611c4b8282610ce0565b15611d1e57600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611cc361100b565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611d4a836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612152565b905092915050565b611d5a610bb7565b611d99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d9090613558565b60405180910390fd5b565b611da3610bb7565b15611de3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dda906135c4565b60405180910390fd5b565b6000826000018281548110611dfd57611dfc6135e4565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b611e2c838383612266565b611e34610bb7565b15611e74576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e6b90613685565b60405180910390fd5b505050565b6060611e9f8273ffffffffffffffffffffffffffffffffffffffff16601460ff16611ea6565b9050919050565b606060006002836002611eb991906136a5565b611ec39190612c2d565b67ffffffffffffffff811115611edc57611edb612378565b5b6040519080825280601f01601f191660200182016040528015611f0e5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611f4657611f456135e4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611faa57611fa96135e4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611fea91906136a5565b611ff49190612c2d565b90505b6001811115612094577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612036576120356135e4565b5b1a60f81b82828151811061204d5761204c6135e4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c94508061208d906136e7565b9050611ff7565b50600084146120d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120cf9061375c565b60405180910390fd5b8091505092915050565b60006120ee838361226b565b61214757826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905061214c565b600090505b92915050565b6000808360010160008481526020019081526020016000205490506000811461225a576000600182612184919061377c565b905060006001866000018054905061219c919061377c565b905081811461220b5760008660000182815481106121bd576121bc6135e4565b5b90600052602060002001549050808760000184815481106121e1576121e06135e4565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b8560000180548061221f5761221e6137b0565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612260565b60009150505b92915050565b505050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6122d7816122a2565b81146122e257600080fd5b50565b6000813590506122f4816122ce565b92915050565b6000602082840312156123105761230f612298565b5b600061231e848285016122e5565b91505092915050565b60008115159050919050565b61233c81612327565b82525050565b60006020820190506123576000830184612333565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6123b082612367565b810181811067ffffffffffffffff821117156123cf576123ce612378565b5b80604052505050565b60006123e261228e565b90506123ee82826123a7565b919050565b600067ffffffffffffffff82111561240e5761240d612378565b5b61241782612367565b9050602081019050919050565b82818337600083830152505050565b6000612446612441846123f3565b6123d8565b90508281526020810184848401111561246257612461612362565b5b61246d848285612424565b509392505050565b600082601f83011261248a5761248961235d565b5b813561249a848260208601612433565b91505092915050565b6000819050919050565b6124b6816124a3565b81146124c157600080fd5b50565b6000813590506124d3816124ad565b92915050565b600080604083850312156124f0576124ef612298565b5b600083013567ffffffffffffffff81111561250e5761250d61229d565b5b61251a85828601612475565b925050602061252b858286016124c4565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561256f578082015181840152602081019050612554565b60008484015250505050565b600061258682612535565b6125908185612540565b93506125a0818560208601612551565b6125a981612367565b840191505092915050565b600060208201905081810360008301526125ce818461257b565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612601826125d6565b9050919050565b612611816125f6565b811461261c57600080fd5b50565b60008135905061262e81612608565b92915050565b6000806040838503121561264b5761264a612298565b5b60006126598582860161261f565b925050602061266a858286016124c4565b9150509250929050565b61267d816124a3565b82525050565b60006020820190506126986000830184612674565b92915050565b6000806000606084860312156126b7576126b6612298565b5b60006126c58682870161261f565b93505060206126d68682870161261f565b92505060406126e7868287016124c4565b9150509250925092565b6000819050919050565b612704816126f1565b811461270f57600080fd5b50565b600081359050612721816126fb565b92915050565b60006020828403121561273d5761273c612298565b5b600061274b84828501612712565b91505092915050565b61275d816126f1565b82525050565b60006020820190506127786000830184612754565b92915050565b6000806040838503121561279557612794612298565b5b60006127a385828601612712565b92505060206127b48582860161261f565b9150509250929050565b600060ff82169050919050565b6127d4816127be565b82525050565b60006020820190506127ef60008301846127cb565b92915050565b60006020828403121561280b5761280a612298565b5b6000612819848285016124c4565b91505092915050565b60006020828403121561283857612837612298565b5b60006128468482850161261f565b91505092915050565b6000806040838503121561286657612865612298565b5b600061287485828601612712565b9250506020612885858286016124c4565b9150509250929050565b612898816125f6565b82525050565b60006020820190506128b3600083018461288f565b92915050565b600080604083850312156128d0576128cf612298565b5b60006128de8582860161261f565b92505060206128ef8582860161261f565b9150509250929050565b600060608201905061290e600083018661288f565b8181036020830152612920818561257b565b905061292f6040830184612674565b949350505050565b61294081612327565b811461294b57600080fd5b50565b60008151905061295d81612937565b92915050565b60006020828403121561297957612978612298565b5b60006129878482850161294e565b91505092915050565b7f6661696c656420746f207374616b650000000000000000000000000000000000600082015250565b60006129c6600f83612540565b91506129d182612990565b602082019050919050565b600060208201905081810360008301526129f5816129b9565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680612a4357607f821691505b602082108103612a5657612a556129fc565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b6000612ab8603883612540565b9150612ac382612a5c565b604082019050919050565b60006020820190508181036000830152612ae781612aab565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612b4a602f83612540565b9150612b5582612aee565b604082019050919050565b60006020820190508181036000830152612b7981612b3d565b9050919050565b6000819050919050565b600063ffffffff82169050919050565b6000819050919050565b6000612bbf612bba612bb584612b80565b612b9a565b612b8a565b9050919050565b612bcf81612ba4565b82525050565b6000604082019050612bea600083018561288f565b612bf76020830184612bc6565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612c38826124a3565b9150612c43836124a3565b9250828201905080821115612c5b57612c5a612bfe565b5b92915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b6000612cbd603b83612540565b9150612cc882612c61565b604082019050919050565b60006020820190508181036000830152612cec81612cb0565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b6000612d4f603883612540565b9150612d5a82612cf3565b604082019050919050565b60006020820190508181036000830152612d7e81612d42565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612de1603983612540565b9150612dec82612d85565b604082019050919050565b60006020820190508181036000830152612e1081612dd4565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612e73602583612540565b9150612e7e82612e17565b604082019050919050565b60006020820190508181036000830152612ea281612e66565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612f05602483612540565b9150612f1082612ea9565b604082019050919050565b60006020820190508181036000830152612f3481612ef8565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612f97602283612540565b9150612fa282612f3b565b604082019050919050565b60006020820190508181036000830152612fc681612f8a565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b6000613029602183612540565b915061303482612fcd565b604082019050919050565b600060208201905081810360008301526130588161301c565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b60006130bb602283612540565b91506130c68261305f565b604082019050919050565b600060208201905081810360008301526130ea816130ae565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b6000613127601d83612540565b9150613132826130f1565b602082019050919050565b600060208201905081810360008301526131568161311a565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b60006131b9602583612540565b91506131c48261315d565b604082019050919050565b600060208201905081810360008301526131e8816131ac565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b600061324b602383612540565b9150613256826131ef565b604082019050919050565b6000602082019050818103600083015261327a8161323e565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006132dd602683612540565b91506132e882613281565b604082019050919050565b6000602082019050818103600083015261330c816132d0565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b6000613349601f83612540565b915061335482613313565b602082019050919050565b600060208201905081810360008301526133788161333c565b9050919050565b6000606082019050613394600083018661288f565b6133a1602083018561288f565b6133ae6040830184612674565b949350505050565b60006133c1826124a3565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036133f3576133f2612bfe565b5b600182019050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b600061343f6017836133fe565b915061344a82613409565b601782019050919050565b600061346082612535565b61346a81856133fe565b935061347a818560208601612551565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006134bc6011836133fe565b91506134c782613486565b601182019050919050565b60006134dd82613432565b91506134e98285613455565b91506134f4826134af565b91506135008284613455565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000613542601483612540565b915061354d8261350c565b602082019050919050565b6000602082019050818103600083015261357181613535565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b60006135ae601083612540565b91506135b982613578565b602082019050919050565b600060208201905081810360008301526135dd816135a1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b600061366f602a83612540565b915061367a82613613565b604082019050919050565b6000602082019050818103600083015261369e81613662565b9050919050565b60006136b0826124a3565b91506136bb836124a3565b92508282026136c9816124a3565b915082820484148315176136e0576136df612bfe565b5b5092915050565b60006136f2826124a3565b91506000820361370557613704612bfe565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000613746602083612540565b915061375182613710565b602082019050919050565b6000602082019050818103600083015261377581613739565b9050919050565b6000613787826124a3565b9150613792836124a3565b92508282039050818111156137aa576137a9612bfe565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ea52cb3272a256f62b695ae21937377a7ea8ac6a47f3579126b1a2b8ae945be764736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806342966c681161010f578063a217fddf116100a2578063d539139311610071578063d5391393146105b9578063d547741f146105d7578063dd62ed3e146105f3578063e63ab1e914610623576101f0565b8063a217fddf1461050b578063a457c2d714610529578063a9059cbb14610559578063ca15c87314610589576101f0565b80638456cb59116100de5780638456cb59146104835780639010d07c1461048d57806391d14854146104bd57806395d89b41146104ed576101f0565b806342966c68146103fd5780635c975abb1461041957806370a082311461043757806379cc679014610467576101f0565b8063282c51f311610187578063372500ab11610156578063372500ab1461039d57806339509351146103a75780633f4ba83a146103d757806340c10f19146103e1576101f0565b8063282c51f3146103295780632f2ff15d14610347578063313ce5671461036357806336568abe14610381576101f0565b806318160ddd116101c357806318160ddd1461028f5780631cf2c7e2146102ad57806323b872dd146102c9578063248a9ca3146102f9576101f0565b806301ffc9a7146101f557806303f24de11461022557806306fdde0314610241578063095ea7b31461025f575b600080fd5b61020f600480360381019061020a91906122fa565b610641565b60405161021c9190612342565b60405180910390f35b61023f600480360381019061023a91906124d9565b6106bb565b005b610249610786565b60405161025691906125b4565b60405180910390f35b61027960048036038101906102749190612634565b610818565b6040516102869190612342565b60405180910390f35b61029761083b565b6040516102a49190612683565b60405180910390f35b6102c760048036038101906102c29190612634565b610845565b005b6102e360048036038101906102de919061269e565b6108c3565b6040516102f09190612342565b60405180910390f35b610313600480360381019061030e9190612727565b6108f2565b6040516103209190612763565b60405180910390f35b610331610911565b60405161033e9190612763565b60405180910390f35b610361600480360381019061035c919061277e565b610935565b005b61036b610956565b60405161037891906127da565b60405180910390f35b61039b6004803603810190610396919061277e565b61096d565b005b6103a56109f0565b005b6103c160048036038101906103bc9190612634565b610a74565b6040516103ce9190612342565b60405180910390f35b6103df610aab565b005b6103fb60048036038101906103f69190612634565b610b25565b005b610417600480360381019061041291906127f5565b610ba3565b005b610421610bb7565b60405161042e9190612342565b60405180910390f35b610451600480360381019061044c9190612822565b610bce565b60405161045e9190612683565b60405180910390f35b610481600480360381019061047c9190612634565b610c17565b005b61048b610c37565b005b6104a760048036038101906104a2919061284f565b610cb1565b6040516104b4919061289e565b60405180910390f35b6104d760048036038101906104d2919061277e565b610ce0565b6040516104e49190612342565b60405180910390f35b6104f5610d4a565b60405161050291906125b4565b60405180910390f35b610513610ddc565b6040516105209190612763565b60405180910390f35b610543600480360381019061053e9190612634565b610de3565b6040516105509190612342565b60405180910390f35b610573600480360381019061056e9190612634565b610e5a565b6040516105809190612342565b60405180910390f35b6105a3600480360381019061059e9190612727565b610e7d565b6040516105b09190612683565b60405180910390f35b6105c1610ea1565b6040516105ce9190612763565b60405180910390f35b6105f160048036038101906105ec919061277e565b610ec5565b005b61060d600480360381019061060891906128b9565b610ee6565b60405161061a9190612683565b60405180910390f35b61062b610f6d565b6040516106389190612763565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106b457506106b382610f91565b5b9050919050565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3085856040518463ffffffff1660e01b81526004016106fc939291906128f9565b6020604051808303816000875af115801561071b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073f9190612963565b905080610781576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610778906129dc565b60405180910390fd5b505050565b60606005805461079590612a2b565b80601f01602080910402602001604051908101604052809291908181526020018280546107c190612a2b565b801561080e5780601f106107e35761010080835404028352916020019161080e565b820191906000526020600020905b8154815290600101906020018083116107f157829003601f168201915b5050505050905090565b60008061082361100b565b9050610830818585611013565b600191505092915050565b6000600454905090565b6108767f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84861087161100b565b610ce0565b6108b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ac90612ace565b60405180910390fd5b6108bf82826111dc565b5050565b6000806108ce61100b565b90506108db8582856113ab565b6108e6858585611437565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b61093e826108f2565b610947816116b0565b61095183836116c4565b505050565b6000600760019054906101000a900460ff16905090565b61097561100b565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146109e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d990612b60565b60405180910390fd5b6109ec82826116f8565b5050565b61080173ffffffffffffffffffffffffffffffffffffffff16632efe8a5f3060646040518363ffffffff1660e01b8152600401610a2e929190612bd5565b6020604051808303816000875af1158015610a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a719190612963565b50565b600080610a7f61100b565b9050610aa0818585610a918589610ee6565b610a9b9190612c2d565b611013565b600191505092915050565b610adc7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610ad761100b565b610ce0565b610b1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1290612cd3565b60405180910390fd5b610b2361172c565b565b610b567f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610b5161100b565b610ce0565b610b95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8c90612d65565b60405180910390fd5b610b9f828261178f565b5050565b610bb4610bae61100b565b826111dc565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b610c2982610c2361100b565b836113ab565b610c3382826111dc565b5050565b610c687f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610c6361100b565b610ce0565b610ca7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9e90612df7565b60405180910390fd5b610caf6118e6565b565b6000610cd8826001600086815260200190815260200160002061194990919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610d5990612a2b565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8590612a2b565b8015610dd25780601f10610da757610100808354040283529160200191610dd2565b820191906000526020600020905b815481529060010190602001808311610db557829003601f168201915b5050505050905090565b6000801b81565b600080610dee61100b565b90506000610dfc8286610ee6565b905083811015610e41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3890612e89565b60405180910390fd5b610e4e8286868403611013565b60019250505092915050565b600080610e6561100b565b9050610e72818585611437565b600191505092915050565b6000610e9a60016000848152602001908152602001600020611963565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610ece826108f2565b610ed7816116b0565b610ee183836116f8565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611004575061100382611978565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611082576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107990612f1b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110e890612fad565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516111cf9190612683565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361124b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112429061303f565b60405180910390fd5b611257826000836119e2565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156112de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d5906130d1565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516113929190612683565b60405180910390a36113a683600084611aa7565b505050565b60006113b78484610ee6565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114315781811015611423576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141a9061313d565b60405180910390fd5b6114308484848403611013565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036114a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149d906131cf565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611515576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150c90613261565b60405180910390fd5b6115208383836119e2565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156115a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159e906132f3565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516116979190612683565b60405180910390a36116aa848484611aa7565b50505050565b6116c1816116bc61100b565b611aac565b50565b6116ce8282611b31565b6116f38160016000858152602001908152602001600020611c1190919063ffffffff16565b505050565b6117028282611c41565b6117278160016000858152602001908152602001600020611d2290919063ffffffff16565b505050565b611734611d52565b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61177861100b565b604051611785919061289e565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036117fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117f59061335f565b60405180910390fd5b61180a600083836119e2565b806004600082825461181c9190612c2d565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118ce9190612683565b60405180910390a36118e260008383611aa7565b5050565b6118ee611d9b565b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861193261100b565b60405161193f919061289e565b60405180910390a1565b60006119588360000183611de5565b60001c905092915050565b600061197182600001611e10565b9050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b7f6a7461657441bf111caa502b48bec73847d91c1265dc315d914c2d2a6c95fcfe838383604051611a159392919061337f565b60405180910390a160005b6005811015611a96573073ffffffffffffffffffffffffffffffffffffffff1663372500ab6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a7157600080fd5b505af1925050508015611a82575060015b508080611a8e906133b6565b915050611a20565b50611aa2838383611e21565b505050565b505050565b611ab68282610ce0565b611b2d57611ac381611e79565b611ad18360001c6020611ea6565b604051602001611ae29291906134d2565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2491906125b4565b60405180910390fd5b5050565b611b3b8282610ce0565b611c0d57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611bb261100b565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611c39836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6120e2565b905092915050565b611c4b8282610ce0565b15611d1e57600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611cc361100b565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611d4a836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612152565b905092915050565b611d5a610bb7565b611d99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d9090613558565b60405180910390fd5b565b611da3610bb7565b15611de3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dda906135c4565b60405180910390fd5b565b6000826000018281548110611dfd57611dfc6135e4565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b611e2c838383612266565b611e34610bb7565b15611e74576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e6b90613685565b60405180910390fd5b505050565b6060611e9f8273ffffffffffffffffffffffffffffffffffffffff16601460ff16611ea6565b9050919050565b606060006002836002611eb991906136a5565b611ec39190612c2d565b67ffffffffffffffff811115611edc57611edb612378565b5b6040519080825280601f01601f191660200182016040528015611f0e5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611f4657611f456135e4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611faa57611fa96135e4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611fea91906136a5565b611ff49190612c2d565b90505b6001811115612094577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612036576120356135e4565b5b1a60f81b82828151811061204d5761204c6135e4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c94508061208d906136e7565b9050611ff7565b50600084146120d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120cf9061375c565b60405180910390fd5b8091505092915050565b60006120ee838361226b565b61214757826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905061214c565b600090505b92915050565b6000808360010160008481526020019081526020016000205490506000811461225a576000600182612184919061377c565b905060006001866000018054905061219c919061377c565b905081811461220b5760008660000182815481106121bd576121bc6135e4565b5b90600052602060002001549050808760000184815481106121e1576121e06135e4565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b8560000180548061221f5761221e6137b0565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612260565b60009150505b92915050565b505050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6122d7816122a2565b81146122e257600080fd5b50565b6000813590506122f4816122ce565b92915050565b6000602082840312156123105761230f612298565b5b600061231e848285016122e5565b91505092915050565b60008115159050919050565b61233c81612327565b82525050565b60006020820190506123576000830184612333565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6123b082612367565b810181811067ffffffffffffffff821117156123cf576123ce612378565b5b80604052505050565b60006123e261228e565b90506123ee82826123a7565b919050565b600067ffffffffffffffff82111561240e5761240d612378565b5b61241782612367565b9050602081019050919050565b82818337600083830152505050565b6000612446612441846123f3565b6123d8565b90508281526020810184848401111561246257612461612362565b5b61246d848285612424565b509392505050565b600082601f83011261248a5761248961235d565b5b813561249a848260208601612433565b91505092915050565b6000819050919050565b6124b6816124a3565b81146124c157600080fd5b50565b6000813590506124d3816124ad565b92915050565b600080604083850312156124f0576124ef612298565b5b600083013567ffffffffffffffff81111561250e5761250d61229d565b5b61251a85828601612475565b925050602061252b858286016124c4565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561256f578082015181840152602081019050612554565b60008484015250505050565b600061258682612535565b6125908185612540565b93506125a0818560208601612551565b6125a981612367565b840191505092915050565b600060208201905081810360008301526125ce818461257b565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612601826125d6565b9050919050565b612611816125f6565b811461261c57600080fd5b50565b60008135905061262e81612608565b92915050565b6000806040838503121561264b5761264a612298565b5b60006126598582860161261f565b925050602061266a858286016124c4565b9150509250929050565b61267d816124a3565b82525050565b60006020820190506126986000830184612674565b92915050565b6000806000606084860312156126b7576126b6612298565b5b60006126c58682870161261f565b93505060206126d68682870161261f565b92505060406126e7868287016124c4565b9150509250925092565b6000819050919050565b612704816126f1565b811461270f57600080fd5b50565b600081359050612721816126fb565b92915050565b60006020828403121561273d5761273c612298565b5b600061274b84828501612712565b91505092915050565b61275d816126f1565b82525050565b60006020820190506127786000830184612754565b92915050565b6000806040838503121561279557612794612298565b5b60006127a385828601612712565b92505060206127b48582860161261f565b9150509250929050565b600060ff82169050919050565b6127d4816127be565b82525050565b60006020820190506127ef60008301846127cb565b92915050565b60006020828403121561280b5761280a612298565b5b6000612819848285016124c4565b91505092915050565b60006020828403121561283857612837612298565b5b60006128468482850161261f565b91505092915050565b6000806040838503121561286657612865612298565b5b600061287485828601612712565b9250506020612885858286016124c4565b9150509250929050565b612898816125f6565b82525050565b60006020820190506128b3600083018461288f565b92915050565b600080604083850312156128d0576128cf612298565b5b60006128de8582860161261f565b92505060206128ef8582860161261f565b9150509250929050565b600060608201905061290e600083018661288f565b8181036020830152612920818561257b565b905061292f6040830184612674565b949350505050565b61294081612327565b811461294b57600080fd5b50565b60008151905061295d81612937565b92915050565b60006020828403121561297957612978612298565b5b60006129878482850161294e565b91505092915050565b7f6661696c656420746f207374616b650000000000000000000000000000000000600082015250565b60006129c6600f83612540565b91506129d182612990565b602082019050919050565b600060208201905081810360008301526129f5816129b9565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680612a4357607f821691505b602082108103612a5657612a556129fc565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b6000612ab8603883612540565b9150612ac382612a5c565b604082019050919050565b60006020820190508181036000830152612ae781612aab565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612b4a602f83612540565b9150612b5582612aee565b604082019050919050565b60006020820190508181036000830152612b7981612b3d565b9050919050565b6000819050919050565b600063ffffffff82169050919050565b6000819050919050565b6000612bbf612bba612bb584612b80565b612b9a565b612b8a565b9050919050565b612bcf81612ba4565b82525050565b6000604082019050612bea600083018561288f565b612bf76020830184612bc6565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612c38826124a3565b9150612c43836124a3565b9250828201905080821115612c5b57612c5a612bfe565b5b92915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b6000612cbd603b83612540565b9150612cc882612c61565b604082019050919050565b60006020820190508181036000830152612cec81612cb0565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b6000612d4f603883612540565b9150612d5a82612cf3565b604082019050919050565b60006020820190508181036000830152612d7e81612d42565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612de1603983612540565b9150612dec82612d85565b604082019050919050565b60006020820190508181036000830152612e1081612dd4565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612e73602583612540565b9150612e7e82612e17565b604082019050919050565b60006020820190508181036000830152612ea281612e66565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612f05602483612540565b9150612f1082612ea9565b604082019050919050565b60006020820190508181036000830152612f3481612ef8565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612f97602283612540565b9150612fa282612f3b565b604082019050919050565b60006020820190508181036000830152612fc681612f8a565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b6000613029602183612540565b915061303482612fcd565b604082019050919050565b600060208201905081810360008301526130588161301c565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b60006130bb602283612540565b91506130c68261305f565b604082019050919050565b600060208201905081810360008301526130ea816130ae565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b6000613127601d83612540565b9150613132826130f1565b602082019050919050565b600060208201905081810360008301526131568161311a565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b60006131b9602583612540565b91506131c48261315d565b604082019050919050565b600060208201905081810360008301526131e8816131ac565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b600061324b602383612540565b9150613256826131ef565b604082019050919050565b6000602082019050818103600083015261327a8161323e565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006132dd602683612540565b91506132e882613281565b604082019050919050565b6000602082019050818103600083015261330c816132d0565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b6000613349601f83612540565b915061335482613313565b602082019050919050565b600060208201905081810360008301526133788161333c565b9050919050565b6000606082019050613394600083018661288f565b6133a1602083018561288f565b6133ae6040830184612674565b949350505050565b60006133c1826124a3565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036133f3576133f2612bfe565b5b600182019050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b600061343f6017836133fe565b915061344a82613409565b601782019050919050565b600061346082612535565b61346a81856133fe565b935061347a818560208601612551565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006134bc6011836133fe565b91506134c782613486565b601182019050919050565b60006134dd82613432565b91506134e98285613455565b91506134f4826134af565b91506135008284613455565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000613542601483612540565b915061354d8261350c565b602082019050919050565b6000602082019050818103600083015261357181613535565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b60006135ae601083612540565b91506135b982613578565b602082019050919050565b600060208201905081810360008301526135dd816135a1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b600061366f602a83612540565b915061367a82613613565b604082019050919050565b6000602082019050818103600083015261369e81613662565b9050919050565b60006136b0826124a3565b91506136bb836124a3565b92508282026136c9816124a3565b915082820484148315176136e0576136df612bfe565b5b5092915050565b60006136f2826124a3565b91506000820361370557613704612bfe565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000613746602083612540565b915061375182613710565b602082019050919050565b6000602082019050818103600083015261377581613739565b9050919050565b6000613787826124a3565b9150613792836124a3565b92508282039050818111156137aa576137a9612bfe565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ea52cb3272a256f62b695ae21937377a7ea8ac6a47f3579126b1a2b8ae945be764736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/ERC20RecursiveNonRevertingPrecompileCall.sol b/contracts/solidity/ERC20RecursiveNonRevertingPrecompileCall.sol new file mode 100644 index 00000000..3ebb391a --- /dev/null +++ b/contracts/solidity/ERC20RecursiveNonRevertingPrecompileCall.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.3.2 (token/ERC20/presets/ERC20PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; +import "./precompiles/distribution/DistributionI.sol" as distribution; +import "./precompiles/staking/StakingI.sol" as staking; +import "./precompiles/bech32/Bech32I.sol" as bech32; +import "./precompiles/common/Types.sol"; + +/** + * @dev {ERC20} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + */ +contract ERC20RecursiveNonRevertingPrecompileCall is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + uint8 private _decimals; + + event BeforeTokenTransferHookCalled(address from, address to, uint256 amount); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract and customizes tokens decimals + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol, uint8 decimals_) + ERC20(name, symbol) { + _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _grantRole(MINTER_ROLE, _msgSender()); + _grantRole(PAUSER_ROLE, _msgSender()); + _grantRole(BURNER_ROLE, _msgSender()); + _setupDecimals(decimals_); + } + + /** + * @dev Sets `_decimals` as `decimals_ once at Deployment' + */ + function _setupDecimals(uint8 decimals_) private { + _decimals = decimals_; + } + + /** + * @dev Overrides the `decimals()` method with custom `_decimals` + */ + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint"); + _mint(to, amount); + } + + /** + * @dev Destroys `amount` new tokens for `to`. + * + * See {ERC20-_burn}. + * + * Requirements: + * + * - the caller must have the `BURNER_ROLE`. + */ + function burnCoins(address from, uint256 amount) public virtual { + require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn"); + _burn(from, amount); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + // Emit an event to track if this hook is called + emit BeforeTokenTransferHookCalled(from, to, amount); + + for(uint256 i=0; i < 5; i++) { + try ERC20RecursiveNonRevertingPrecompileCall(address(this)).claimRewards() { + + } catch { + + } + + } + + super._beforeTokenTransfer(from, to, amount); + } + + function delegate( + string memory validatorAddress, + uint256 amount + ) external { + bool ok = staking.STAKING_CONTRACT.delegate(address(this), validatorAddress, amount); + require(ok, "failed to stake"); + } + + function claimRewards() public { + distribution.DISTRIBUTION_CONTRACT.claimRewards(address(this), 100); + } +} \ No newline at end of file diff --git a/contracts/solidity/ERC20RecursiveRevertingPrecompileCall.json b/contracts/solidity/ERC20RecursiveRevertingPrecompileCall.json new file mode 100644 index 00000000..73424a1e --- /dev/null +++ b/contracts/solidity/ERC20RecursiveRevertingPrecompileCall.json @@ -0,0 +1,758 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20RecursiveRevertingPrecompileCall", + "sourceName": "solidity/ERC20RecursiveRevertingPrecompileCall.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "BeforeTokenTransferHookCalled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "BURNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnCoins", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimRewardsAndRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "validatorAddress", + "type": "string" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getRoleMember", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleMemberCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b50604051620041d3380380620041d38339818101604052810190620000379190620005e0565b828281600590816200004a9190620008c5565b5080600690816200005c9190620008c5565b5050506000600760006101000a81548160ff0219169083151502179055506200009e6000801b620000926200017b60201b60201c565b6200018360201b60201c565b620000df7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6620000d36200017b60201b60201c565b6200018360201b60201c565b620001207f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a620001146200017b60201b60201c565b6200018360201b60201c565b620001617f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848620001556200017b60201b60201c565b6200018360201b60201c565b6200017281620001c160201b60201c565b505050620009ac565b600033905090565b620001958282620001df60201b60201c565b620001bc8160016000858152602001908152602001600020620002d060201b90919060201c565b505050565b80600760016101000a81548160ff021916908360ff16021790555050565b620001f182826200030860201b60201c565b620002cc57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620002716200017b60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600062000300836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6200037260201b60201c565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000620003868383620003ec60201b60201c565b620003e1578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050620003e6565b600090505b92915050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000478826200042d565b810181811067ffffffffffffffff821117156200049a57620004996200043e565b5b80604052505050565b6000620004af6200040f565b9050620004bd82826200046d565b919050565b600067ffffffffffffffff821115620004e057620004df6200043e565b5b620004eb826200042d565b9050602081019050919050565b60005b8381101562000518578082015181840152602081019050620004fb565b60008484015250505050565b60006200053b6200053584620004c2565b620004a3565b9050828152602081018484840111156200055a576200055962000428565b5b62000567848285620004f8565b509392505050565b600082601f83011262000587576200058662000423565b5b81516200059984826020860162000524565b91505092915050565b600060ff82169050919050565b620005ba81620005a2565b8114620005c657600080fd5b50565b600081519050620005da81620005af565b92915050565b600080600060608486031215620005fc57620005fb62000419565b5b600084015167ffffffffffffffff8111156200061d576200061c6200041e565b5b6200062b868287016200056f565b935050602084015167ffffffffffffffff8111156200064f576200064e6200041e565b5b6200065d868287016200056f565b92505060406200067086828701620005c9565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006cd57607f821691505b602082108103620006e357620006e262000685565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200074d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200070e565b6200075986836200070e565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620007a6620007a06200079a8462000771565b6200077b565b62000771565b9050919050565b6000819050919050565b620007c28362000785565b620007da620007d182620007ad565b8484546200071b565b825550505050565b600090565b620007f1620007e2565b620007fe818484620007b7565b505050565b5b8181101562000826576200081a600082620007e7565b60018101905062000804565b5050565b601f82111562000875576200083f81620006e9565b6200084a84620006fe565b810160208510156200085a578190505b620008726200086985620006fe565b83018262000803565b50505b505050565b600082821c905092915050565b60006200089a600019846008026200087a565b1980831691505092915050565b6000620008b5838362000887565b9150826002028217905092915050565b620008d0826200067a565b67ffffffffffffffff811115620008ec57620008eb6200043e565b5b620008f88254620006b4565b620009058282856200082a565b600060209050601f8311600181146200093d576000841562000928578287015190505b620009348582620008a7565b865550620009a4565b601f1984166200094d86620006e9565b60005b82811015620009775784890151825560018201915060208501945060208101905062000950565b8683101562000997578489015162000993601f89168262000887565b8355505b6001600288020188555050505b505050505050565b61381780620009bc6000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806342966c681161010f578063a217fddf116100a2578063d539139311610071578063d5391393146105b9578063d547741f146105d7578063dd62ed3e146105f3578063e63ab1e914610623576101f0565b8063a217fddf1461050b578063a457c2d714610529578063a9059cbb14610559578063ca15c87314610589576101f0565b80638456cb59116100de5780638456cb59146104835780639010d07c1461048d57806391d14854146104bd57806395d89b41146104ed576101f0565b806342966c68146103fd5780635c975abb1461041957806370a082311461043757806379cc679014610467576101f0565b8063282c51f31161018757806336568abe1161015657806336568abe1461038b57806339509351146103a75780633f4ba83a146103d757806340c10f19146103e1576101f0565b8063282c51f3146103295780632c0503d4146103475780632f2ff15d14610351578063313ce5671461036d576101f0565b806318160ddd116101c357806318160ddd1461028f5780631cf2c7e2146102ad57806323b872dd146102c9578063248a9ca3146102f9576101f0565b806301ffc9a7146101f557806303f24de11461022557806306fdde0314610241578063095ea7b31461025f575b600080fd5b61020f600480360381019061020a91906122fc565b610641565b60405161021c9190612344565b60405180910390f35b61023f600480360381019061023a91906124db565b6106bb565b005b610249610786565b60405161025691906125b6565b60405180910390f35b61027960048036038101906102749190612636565b610818565b6040516102869190612344565b60405180910390f35b61029761083b565b6040516102a49190612685565b60405180910390f35b6102c760048036038101906102c29190612636565b610845565b005b6102e360048036038101906102de91906126a0565b6108c3565b6040516102f09190612344565b60405180910390f35b610313600480360381019061030e9190612729565b6108f2565b6040516103209190612765565b60405180910390f35b610331610911565b60405161033e9190612765565b60405180910390f35b61034f610935565b005b61036b60048036038101906103669190612780565b6109bb565b005b6103756109dc565b60405161038291906127dc565b60405180910390f35b6103a560048036038101906103a09190612780565b6109f3565b005b6103c160048036038101906103bc9190612636565b610a76565b6040516103ce9190612344565b60405180910390f35b6103df610aad565b005b6103fb60048036038101906103f69190612636565b610b27565b005b610417600480360381019061041291906127f7565b610ba5565b005b610421610bb9565b60405161042e9190612344565b60405180910390f35b610451600480360381019061044c9190612824565b610bd0565b60405161045e9190612685565b60405180910390f35b610481600480360381019061047c9190612636565b610c19565b005b61048b610c39565b005b6104a760048036038101906104a29190612851565b610cb3565b6040516104b491906128a0565b60405180910390f35b6104d760048036038101906104d29190612780565b610ce2565b6040516104e49190612344565b60405180910390f35b6104f5610d4c565b60405161050291906125b6565b60405180910390f35b610513610dde565b6040516105209190612765565b60405180910390f35b610543600480360381019061053e9190612636565b610de5565b6040516105509190612344565b60405180910390f35b610573600480360381019061056e9190612636565b610e5c565b6040516105809190612344565b60405180910390f35b6105a3600480360381019061059e9190612729565b610e7f565b6040516105b09190612685565b60405180910390f35b6105c1610ea3565b6040516105ce9190612765565b60405180910390f35b6105f160048036038101906105ec9190612780565b610ec7565b005b61060d600480360381019061060891906128bb565b610ee8565b60405161061a9190612685565b60405180910390f35b61062b610f6f565b6040516106389190612765565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106b457506106b382610f93565b5b9050919050565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3085856040518463ffffffff1660e01b81526004016106fc939291906128fb565b6020604051808303816000875af115801561071b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073f9190612965565b905080610781576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610778906129de565b60405180910390fd5b505050565b60606005805461079590612a2d565b80601f01602080910402602001604051908101604052809291908181526020018280546107c190612a2d565b801561080e5780601f106107e35761010080835404028352916020019161080e565b820191906000526020600020905b8154815290600101906020018083116107f157829003601f168201915b5050505050905090565b60008061082361100d565b9050610830818585611015565b600191505092915050565b6000600454905090565b6108767f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84861087161100d565b610ce2565b6108b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ac90612ad0565b60405180910390fd5b6108bf82826111de565b5050565b6000806108ce61100d565b90506108db8582856113ad565b6108e6858585611439565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b61080173ffffffffffffffffffffffffffffffffffffffff16632efe8a5f3060646040518363ffffffff1660e01b8152600401610973929190612b45565b6020604051808303816000875af1158015610992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b69190612965565b600080fd5b6109c4826108f2565b6109cd816116b2565b6109d783836116c6565b505050565b6000600760019054906101000a900460ff16905090565b6109fb61100d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a68576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5f90612be0565b60405180910390fd5b610a7282826116fa565b5050565b600080610a8161100d565b9050610aa2818585610a938589610ee8565b610a9d9190612c2f565b611015565b600191505092915050565b610ade7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610ad961100d565b610ce2565b610b1d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1490612cd5565b60405180910390fd5b610b2561172e565b565b610b587f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610b5361100d565b610ce2565b610b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8e90612d67565b60405180910390fd5b610ba18282611791565b5050565b610bb6610bb061100d565b826111de565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b610c2b82610c2561100d565b836113ad565b610c3582826111de565b5050565b610c6a7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610c6561100d565b610ce2565b610ca9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca090612df9565b60405180910390fd5b610cb16118e8565b565b6000610cda826001600086815260200190815260200160002061194b90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610d5b90612a2d565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8790612a2d565b8015610dd45780601f10610da957610100808354040283529160200191610dd4565b820191906000526020600020905b815481529060010190602001808311610db757829003601f168201915b5050505050905090565b6000801b81565b600080610df061100d565b90506000610dfe8286610ee8565b905083811015610e43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3a90612e8b565b60405180910390fd5b610e508286868403611015565b60019250505092915050565b600080610e6761100d565b9050610e74818585611439565b600191505092915050565b6000610e9c60016000848152602001908152602001600020611965565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610ed0826108f2565b610ed9816116b2565b610ee383836116fa565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061100657506110058261197a565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611084576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107b90612f1d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110ea90612faf565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516111d19190612685565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361124d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124490613041565b60405180910390fd5b611259826000836119e4565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156112e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d7906130d3565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516113949190612685565b60405180910390a36113a883600084611aa9565b505050565b60006113b98484610ee8565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114335781811015611425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141c9061313f565b60405180910390fd5b6114328484848403611015565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036114a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149f906131d1565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611517576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150e90613263565b60405180910390fd5b6115228383836119e4565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156115a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115a0906132f5565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516116999190612685565b60405180910390a36116ac848484611aa9565b50505050565b6116c3816116be61100d565b611aae565b50565b6116d08282611b33565b6116f58160016000858152602001908152602001600020611c1390919063ffffffff16565b505050565b6117048282611c43565b6117298160016000858152602001908152602001600020611d2490919063ffffffff16565b505050565b611736611d54565b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61177a61100d565b60405161178791906128a0565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611800576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117f790613361565b60405180910390fd5b61180c600083836119e4565b806004600082825461181e9190612c2f565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118d09190612685565b60405180910390a36118e460008383611aa9565b5050565b6118f0611d9d565b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861193461100d565b60405161194191906128a0565b60405180910390a1565b600061195a8360000183611de7565b60001c905092915050565b600061197382600001611e12565b9050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b7f6a7461657441bf111caa502b48bec73847d91c1265dc315d914c2d2a6c95fcfe838383604051611a1793929190613381565b60405180910390a160005b6005811015611a98573073ffffffffffffffffffffffffffffffffffffffff16632c0503d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a7357600080fd5b505af1925050508015611a84575060015b508080611a90906133b8565b915050611a22565b50611aa4838383611e23565b505050565b505050565b611ab88282610ce2565b611b2f57611ac581611e7b565b611ad38360001c6020611ea8565b604051602001611ae49291906134d4565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2691906125b6565b60405180910390fd5b5050565b611b3d8282610ce2565b611c0f57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611bb461100d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611c3b836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6120e4565b905092915050565b611c4d8282610ce2565b15611d2057600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611cc561100d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611d4c836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612154565b905092915050565b611d5c610bb9565b611d9b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d929061355a565b60405180910390fd5b565b611da5610bb9565b15611de5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ddc906135c6565b60405180910390fd5b565b6000826000018281548110611dff57611dfe6135e6565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b611e2e838383612268565b611e36610bb9565b15611e76576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e6d90613687565b60405180910390fd5b505050565b6060611ea18273ffffffffffffffffffffffffffffffffffffffff16601460ff16611ea8565b9050919050565b606060006002836002611ebb91906136a7565b611ec59190612c2f565b67ffffffffffffffff811115611ede57611edd61237a565b5b6040519080825280601f01601f191660200182016040528015611f105781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611f4857611f476135e6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611fac57611fab6135e6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611fec91906136a7565b611ff69190612c2f565b90505b6001811115612096577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612038576120376135e6565b5b1a60f81b82828151811061204f5761204e6135e6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c94508061208f906136e9565b9050611ff9565b50600084146120da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120d19061375e565b60405180910390fd5b8091505092915050565b60006120f0838361226d565b61214957826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905061214e565b600090505b92915050565b6000808360010160008481526020019081526020016000205490506000811461225c576000600182612186919061377e565b905060006001866000018054905061219e919061377e565b905081811461220d5760008660000182815481106121bf576121be6135e6565b5b90600052602060002001549050808760000184815481106121e3576121e26135e6565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b85600001805480612221576122206137b2565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612262565b60009150505b92915050565b505050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6122d9816122a4565b81146122e457600080fd5b50565b6000813590506122f6816122d0565b92915050565b6000602082840312156123125761231161229a565b5b6000612320848285016122e7565b91505092915050565b60008115159050919050565b61233e81612329565b82525050565b60006020820190506123596000830184612335565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6123b282612369565b810181811067ffffffffffffffff821117156123d1576123d061237a565b5b80604052505050565b60006123e4612290565b90506123f082826123a9565b919050565b600067ffffffffffffffff8211156124105761240f61237a565b5b61241982612369565b9050602081019050919050565b82818337600083830152505050565b6000612448612443846123f5565b6123da565b90508281526020810184848401111561246457612463612364565b5b61246f848285612426565b509392505050565b600082601f83011261248c5761248b61235f565b5b813561249c848260208601612435565b91505092915050565b6000819050919050565b6124b8816124a5565b81146124c357600080fd5b50565b6000813590506124d5816124af565b92915050565b600080604083850312156124f2576124f161229a565b5b600083013567ffffffffffffffff8111156125105761250f61229f565b5b61251c85828601612477565b925050602061252d858286016124c6565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612571578082015181840152602081019050612556565b60008484015250505050565b600061258882612537565b6125928185612542565b93506125a2818560208601612553565b6125ab81612369565b840191505092915050565b600060208201905081810360008301526125d0818461257d565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612603826125d8565b9050919050565b612613816125f8565b811461261e57600080fd5b50565b6000813590506126308161260a565b92915050565b6000806040838503121561264d5761264c61229a565b5b600061265b85828601612621565b925050602061266c858286016124c6565b9150509250929050565b61267f816124a5565b82525050565b600060208201905061269a6000830184612676565b92915050565b6000806000606084860312156126b9576126b861229a565b5b60006126c786828701612621565b93505060206126d886828701612621565b92505060406126e9868287016124c6565b9150509250925092565b6000819050919050565b612706816126f3565b811461271157600080fd5b50565b600081359050612723816126fd565b92915050565b60006020828403121561273f5761273e61229a565b5b600061274d84828501612714565b91505092915050565b61275f816126f3565b82525050565b600060208201905061277a6000830184612756565b92915050565b600080604083850312156127975761279661229a565b5b60006127a585828601612714565b92505060206127b685828601612621565b9150509250929050565b600060ff82169050919050565b6127d6816127c0565b82525050565b60006020820190506127f160008301846127cd565b92915050565b60006020828403121561280d5761280c61229a565b5b600061281b848285016124c6565b91505092915050565b60006020828403121561283a5761283961229a565b5b600061284884828501612621565b91505092915050565b600080604083850312156128685761286761229a565b5b600061287685828601612714565b9250506020612887858286016124c6565b9150509250929050565b61289a816125f8565b82525050565b60006020820190506128b56000830184612891565b92915050565b600080604083850312156128d2576128d161229a565b5b60006128e085828601612621565b92505060206128f185828601612621565b9150509250929050565b60006060820190506129106000830186612891565b8181036020830152612922818561257d565b90506129316040830184612676565b949350505050565b61294281612329565b811461294d57600080fd5b50565b60008151905061295f81612939565b92915050565b60006020828403121561297b5761297a61229a565b5b600061298984828501612950565b91505092915050565b7f6661696c656420746f207374616b650000000000000000000000000000000000600082015250565b60006129c8600f83612542565b91506129d382612992565b602082019050919050565b600060208201905081810360008301526129f7816129bb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680612a4557607f821691505b602082108103612a5857612a576129fe565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b6000612aba603883612542565b9150612ac582612a5e565b604082019050919050565b60006020820190508181036000830152612ae981612aad565b9050919050565b6000819050919050565b600063ffffffff82169050919050565b6000819050919050565b6000612b2f612b2a612b2584612af0565b612b0a565b612afa565b9050919050565b612b3f81612b14565b82525050565b6000604082019050612b5a6000830185612891565b612b676020830184612b36565b9392505050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612bca602f83612542565b9150612bd582612b6e565b604082019050919050565b60006020820190508181036000830152612bf981612bbd565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612c3a826124a5565b9150612c45836124a5565b9250828201905080821115612c5d57612c5c612c00565b5b92915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b6000612cbf603b83612542565b9150612cca82612c63565b604082019050919050565b60006020820190508181036000830152612cee81612cb2565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b6000612d51603883612542565b9150612d5c82612cf5565b604082019050919050565b60006020820190508181036000830152612d8081612d44565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612de3603983612542565b9150612dee82612d87565b604082019050919050565b60006020820190508181036000830152612e1281612dd6565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612e75602583612542565b9150612e8082612e19565b604082019050919050565b60006020820190508181036000830152612ea481612e68565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612f07602483612542565b9150612f1282612eab565b604082019050919050565b60006020820190508181036000830152612f3681612efa565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612f99602283612542565b9150612fa482612f3d565b604082019050919050565b60006020820190508181036000830152612fc881612f8c565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b600061302b602183612542565b915061303682612fcf565b604082019050919050565b6000602082019050818103600083015261305a8161301e565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b60006130bd602283612542565b91506130c882613061565b604082019050919050565b600060208201905081810360008301526130ec816130b0565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b6000613129601d83612542565b9150613134826130f3565b602082019050919050565b600060208201905081810360008301526131588161311c565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b60006131bb602583612542565b91506131c68261315f565b604082019050919050565b600060208201905081810360008301526131ea816131ae565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b600061324d602383612542565b9150613258826131f1565b604082019050919050565b6000602082019050818103600083015261327c81613240565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006132df602683612542565b91506132ea82613283565b604082019050919050565b6000602082019050818103600083015261330e816132d2565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600061334b601f83612542565b915061335682613315565b602082019050919050565b6000602082019050818103600083015261337a8161333e565b9050919050565b60006060820190506133966000830186612891565b6133a36020830185612891565b6133b06040830184612676565b949350505050565b60006133c3826124a5565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036133f5576133f4612c00565b5b600182019050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000613441601783613400565b915061344c8261340b565b601782019050919050565b600061346282612537565b61346c8185613400565b935061347c818560208601612553565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006134be601183613400565b91506134c982613488565b601182019050919050565b60006134df82613434565b91506134eb8285613457565b91506134f6826134b1565b91506135028284613457565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000613544601483612542565b915061354f8261350e565b602082019050919050565b6000602082019050818103600083015261357381613537565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b60006135b0601083612542565b91506135bb8261357a565b602082019050919050565b600060208201905081810360008301526135df816135a3565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000613671602a83612542565b915061367c82613615565b604082019050919050565b600060208201905081810360008301526136a081613664565b9050919050565b60006136b2826124a5565b91506136bd836124a5565b92508282026136cb816124a5565b915082820484148315176136e2576136e1612c00565b5b5092915050565b60006136f4826124a5565b91506000820361370757613706612c00565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000613748602083612542565b915061375382613712565b602082019050919050565b600060208201905081810360008301526137778161373b565b9050919050565b6000613789826124a5565b9150613794836124a5565b92508282039050818111156137ac576137ab612c00565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a22989a3c73ef2895da365d02b7572bb6f24e425e460a1a2078ba8e18b66baf564736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806342966c681161010f578063a217fddf116100a2578063d539139311610071578063d5391393146105b9578063d547741f146105d7578063dd62ed3e146105f3578063e63ab1e914610623576101f0565b8063a217fddf1461050b578063a457c2d714610529578063a9059cbb14610559578063ca15c87314610589576101f0565b80638456cb59116100de5780638456cb59146104835780639010d07c1461048d57806391d14854146104bd57806395d89b41146104ed576101f0565b806342966c68146103fd5780635c975abb1461041957806370a082311461043757806379cc679014610467576101f0565b8063282c51f31161018757806336568abe1161015657806336568abe1461038b57806339509351146103a75780633f4ba83a146103d757806340c10f19146103e1576101f0565b8063282c51f3146103295780632c0503d4146103475780632f2ff15d14610351578063313ce5671461036d576101f0565b806318160ddd116101c357806318160ddd1461028f5780631cf2c7e2146102ad57806323b872dd146102c9578063248a9ca3146102f9576101f0565b806301ffc9a7146101f557806303f24de11461022557806306fdde0314610241578063095ea7b31461025f575b600080fd5b61020f600480360381019061020a91906122fc565b610641565b60405161021c9190612344565b60405180910390f35b61023f600480360381019061023a91906124db565b6106bb565b005b610249610786565b60405161025691906125b6565b60405180910390f35b61027960048036038101906102749190612636565b610818565b6040516102869190612344565b60405180910390f35b61029761083b565b6040516102a49190612685565b60405180910390f35b6102c760048036038101906102c29190612636565b610845565b005b6102e360048036038101906102de91906126a0565b6108c3565b6040516102f09190612344565b60405180910390f35b610313600480360381019061030e9190612729565b6108f2565b6040516103209190612765565b60405180910390f35b610331610911565b60405161033e9190612765565b60405180910390f35b61034f610935565b005b61036b60048036038101906103669190612780565b6109bb565b005b6103756109dc565b60405161038291906127dc565b60405180910390f35b6103a560048036038101906103a09190612780565b6109f3565b005b6103c160048036038101906103bc9190612636565b610a76565b6040516103ce9190612344565b60405180910390f35b6103df610aad565b005b6103fb60048036038101906103f69190612636565b610b27565b005b610417600480360381019061041291906127f7565b610ba5565b005b610421610bb9565b60405161042e9190612344565b60405180910390f35b610451600480360381019061044c9190612824565b610bd0565b60405161045e9190612685565b60405180910390f35b610481600480360381019061047c9190612636565b610c19565b005b61048b610c39565b005b6104a760048036038101906104a29190612851565b610cb3565b6040516104b491906128a0565b60405180910390f35b6104d760048036038101906104d29190612780565b610ce2565b6040516104e49190612344565b60405180910390f35b6104f5610d4c565b60405161050291906125b6565b60405180910390f35b610513610dde565b6040516105209190612765565b60405180910390f35b610543600480360381019061053e9190612636565b610de5565b6040516105509190612344565b60405180910390f35b610573600480360381019061056e9190612636565b610e5c565b6040516105809190612344565b60405180910390f35b6105a3600480360381019061059e9190612729565b610e7f565b6040516105b09190612685565b60405180910390f35b6105c1610ea3565b6040516105ce9190612765565b60405180910390f35b6105f160048036038101906105ec9190612780565b610ec7565b005b61060d600480360381019061060891906128bb565b610ee8565b60405161061a9190612685565b60405180910390f35b61062b610f6f565b6040516106389190612765565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106b457506106b382610f93565b5b9050919050565b600061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb3085856040518463ffffffff1660e01b81526004016106fc939291906128fb565b6020604051808303816000875af115801561071b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073f9190612965565b905080610781576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610778906129de565b60405180910390fd5b505050565b60606005805461079590612a2d565b80601f01602080910402602001604051908101604052809291908181526020018280546107c190612a2d565b801561080e5780601f106107e35761010080835404028352916020019161080e565b820191906000526020600020905b8154815290600101906020018083116107f157829003601f168201915b5050505050905090565b60008061082361100d565b9050610830818585611015565b600191505092915050565b6000600454905090565b6108767f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84861087161100d565b610ce2565b6108b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ac90612ad0565b60405180910390fd5b6108bf82826111de565b5050565b6000806108ce61100d565b90506108db8582856113ad565b6108e6858585611439565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b61080173ffffffffffffffffffffffffffffffffffffffff16632efe8a5f3060646040518363ffffffff1660e01b8152600401610973929190612b45565b6020604051808303816000875af1158015610992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b69190612965565b600080fd5b6109c4826108f2565b6109cd816116b2565b6109d783836116c6565b505050565b6000600760019054906101000a900460ff16905090565b6109fb61100d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a68576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5f90612be0565b60405180910390fd5b610a7282826116fa565b5050565b600080610a8161100d565b9050610aa2818585610a938589610ee8565b610a9d9190612c2f565b611015565b600191505092915050565b610ade7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610ad961100d565b610ce2565b610b1d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1490612cd5565b60405180910390fd5b610b2561172e565b565b610b587f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610b5361100d565b610ce2565b610b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8e90612d67565b60405180910390fd5b610ba18282611791565b5050565b610bb6610bb061100d565b826111de565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b610c2b82610c2561100d565b836113ad565b610c3582826111de565b5050565b610c6a7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610c6561100d565b610ce2565b610ca9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca090612df9565b60405180910390fd5b610cb16118e8565b565b6000610cda826001600086815260200190815260200160002061194b90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610d5b90612a2d565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8790612a2d565b8015610dd45780601f10610da957610100808354040283529160200191610dd4565b820191906000526020600020905b815481529060010190602001808311610db757829003601f168201915b5050505050905090565b6000801b81565b600080610df061100d565b90506000610dfe8286610ee8565b905083811015610e43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3a90612e8b565b60405180910390fd5b610e508286868403611015565b60019250505092915050565b600080610e6761100d565b9050610e74818585611439565b600191505092915050565b6000610e9c60016000848152602001908152602001600020611965565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610ed0826108f2565b610ed9816116b2565b610ee383836116fa565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061100657506110058261197a565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611084576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161107b90612f1d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110ea90612faf565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516111d19190612685565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361124d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124490613041565b60405180910390fd5b611259826000836119e4565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156112e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d7906130d3565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516113949190612685565b60405180910390a36113a883600084611aa9565b505050565b60006113b98484610ee8565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114335781811015611425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141c9061313f565b60405180910390fd5b6114328484848403611015565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036114a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149f906131d1565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611517576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150e90613263565b60405180910390fd5b6115228383836119e4565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156115a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115a0906132f5565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516116999190612685565b60405180910390a36116ac848484611aa9565b50505050565b6116c3816116be61100d565b611aae565b50565b6116d08282611b33565b6116f58160016000858152602001908152602001600020611c1390919063ffffffff16565b505050565b6117048282611c43565b6117298160016000858152602001908152602001600020611d2490919063ffffffff16565b505050565b611736611d54565b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61177a61100d565b60405161178791906128a0565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611800576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117f790613361565b60405180910390fd5b61180c600083836119e4565b806004600082825461181e9190612c2f565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118d09190612685565b60405180910390a36118e460008383611aa9565b5050565b6118f0611d9d565b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861193461100d565b60405161194191906128a0565b60405180910390a1565b600061195a8360000183611de7565b60001c905092915050565b600061197382600001611e12565b9050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b7f6a7461657441bf111caa502b48bec73847d91c1265dc315d914c2d2a6c95fcfe838383604051611a1793929190613381565b60405180910390a160005b6005811015611a98573073ffffffffffffffffffffffffffffffffffffffff16632c0503d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a7357600080fd5b505af1925050508015611a84575060015b508080611a90906133b8565b915050611a22565b50611aa4838383611e23565b505050565b505050565b611ab88282610ce2565b611b2f57611ac581611e7b565b611ad38360001c6020611ea8565b604051602001611ae49291906134d4565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2691906125b6565b60405180910390fd5b5050565b611b3d8282610ce2565b611c0f57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611bb461100d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611c3b836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6120e4565b905092915050565b611c4d8282610ce2565b15611d2057600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611cc561100d565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611d4c836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612154565b905092915050565b611d5c610bb9565b611d9b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d929061355a565b60405180910390fd5b565b611da5610bb9565b15611de5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ddc906135c6565b60405180910390fd5b565b6000826000018281548110611dff57611dfe6135e6565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b611e2e838383612268565b611e36610bb9565b15611e76576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e6d90613687565b60405180910390fd5b505050565b6060611ea18273ffffffffffffffffffffffffffffffffffffffff16601460ff16611ea8565b9050919050565b606060006002836002611ebb91906136a7565b611ec59190612c2f565b67ffffffffffffffff811115611ede57611edd61237a565b5b6040519080825280601f01601f191660200182016040528015611f105781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611f4857611f476135e6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611fac57611fab6135e6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611fec91906136a7565b611ff69190612c2f565b90505b6001811115612096577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612038576120376135e6565b5b1a60f81b82828151811061204f5761204e6135e6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c94508061208f906136e9565b9050611ff9565b50600084146120da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120d19061375e565b60405180910390fd5b8091505092915050565b60006120f0838361226d565b61214957826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905061214e565b600090505b92915050565b6000808360010160008481526020019081526020016000205490506000811461225c576000600182612186919061377e565b905060006001866000018054905061219e919061377e565b905081811461220d5760008660000182815481106121bf576121be6135e6565b5b90600052602060002001549050808760000184815481106121e3576121e26135e6565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b85600001805480612221576122206137b2565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612262565b60009150505b92915050565b505050565b600080836001016000848152602001908152602001600020541415905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6122d9816122a4565b81146122e457600080fd5b50565b6000813590506122f6816122d0565b92915050565b6000602082840312156123125761231161229a565b5b6000612320848285016122e7565b91505092915050565b60008115159050919050565b61233e81612329565b82525050565b60006020820190506123596000830184612335565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6123b282612369565b810181811067ffffffffffffffff821117156123d1576123d061237a565b5b80604052505050565b60006123e4612290565b90506123f082826123a9565b919050565b600067ffffffffffffffff8211156124105761240f61237a565b5b61241982612369565b9050602081019050919050565b82818337600083830152505050565b6000612448612443846123f5565b6123da565b90508281526020810184848401111561246457612463612364565b5b61246f848285612426565b509392505050565b600082601f83011261248c5761248b61235f565b5b813561249c848260208601612435565b91505092915050565b6000819050919050565b6124b8816124a5565b81146124c357600080fd5b50565b6000813590506124d5816124af565b92915050565b600080604083850312156124f2576124f161229a565b5b600083013567ffffffffffffffff8111156125105761250f61229f565b5b61251c85828601612477565b925050602061252d858286016124c6565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612571578082015181840152602081019050612556565b60008484015250505050565b600061258882612537565b6125928185612542565b93506125a2818560208601612553565b6125ab81612369565b840191505092915050565b600060208201905081810360008301526125d0818461257d565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612603826125d8565b9050919050565b612613816125f8565b811461261e57600080fd5b50565b6000813590506126308161260a565b92915050565b6000806040838503121561264d5761264c61229a565b5b600061265b85828601612621565b925050602061266c858286016124c6565b9150509250929050565b61267f816124a5565b82525050565b600060208201905061269a6000830184612676565b92915050565b6000806000606084860312156126b9576126b861229a565b5b60006126c786828701612621565b93505060206126d886828701612621565b92505060406126e9868287016124c6565b9150509250925092565b6000819050919050565b612706816126f3565b811461271157600080fd5b50565b600081359050612723816126fd565b92915050565b60006020828403121561273f5761273e61229a565b5b600061274d84828501612714565b91505092915050565b61275f816126f3565b82525050565b600060208201905061277a6000830184612756565b92915050565b600080604083850312156127975761279661229a565b5b60006127a585828601612714565b92505060206127b685828601612621565b9150509250929050565b600060ff82169050919050565b6127d6816127c0565b82525050565b60006020820190506127f160008301846127cd565b92915050565b60006020828403121561280d5761280c61229a565b5b600061281b848285016124c6565b91505092915050565b60006020828403121561283a5761283961229a565b5b600061284884828501612621565b91505092915050565b600080604083850312156128685761286761229a565b5b600061287685828601612714565b9250506020612887858286016124c6565b9150509250929050565b61289a816125f8565b82525050565b60006020820190506128b56000830184612891565b92915050565b600080604083850312156128d2576128d161229a565b5b60006128e085828601612621565b92505060206128f185828601612621565b9150509250929050565b60006060820190506129106000830186612891565b8181036020830152612922818561257d565b90506129316040830184612676565b949350505050565b61294281612329565b811461294d57600080fd5b50565b60008151905061295f81612939565b92915050565b60006020828403121561297b5761297a61229a565b5b600061298984828501612950565b91505092915050565b7f6661696c656420746f207374616b650000000000000000000000000000000000600082015250565b60006129c8600f83612542565b91506129d382612992565b602082019050919050565b600060208201905081810360008301526129f7816129bb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680612a4557607f821691505b602082108103612a5857612a576129fe565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b6000612aba603883612542565b9150612ac582612a5e565b604082019050919050565b60006020820190508181036000830152612ae981612aad565b9050919050565b6000819050919050565b600063ffffffff82169050919050565b6000819050919050565b6000612b2f612b2a612b2584612af0565b612b0a565b612afa565b9050919050565b612b3f81612b14565b82525050565b6000604082019050612b5a6000830185612891565b612b676020830184612b36565b9392505050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612bca602f83612542565b9150612bd582612b6e565b604082019050919050565b60006020820190508181036000830152612bf981612bbd565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612c3a826124a5565b9150612c45836124a5565b9250828201905080821115612c5d57612c5c612c00565b5b92915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b6000612cbf603b83612542565b9150612cca82612c63565b604082019050919050565b60006020820190508181036000830152612cee81612cb2565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b6000612d51603883612542565b9150612d5c82612cf5565b604082019050919050565b60006020820190508181036000830152612d8081612d44565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612de3603983612542565b9150612dee82612d87565b604082019050919050565b60006020820190508181036000830152612e1281612dd6565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612e75602583612542565b9150612e8082612e19565b604082019050919050565b60006020820190508181036000830152612ea481612e68565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612f07602483612542565b9150612f1282612eab565b604082019050919050565b60006020820190508181036000830152612f3681612efa565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612f99602283612542565b9150612fa482612f3d565b604082019050919050565b60006020820190508181036000830152612fc881612f8c565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b600061302b602183612542565b915061303682612fcf565b604082019050919050565b6000602082019050818103600083015261305a8161301e565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b60006130bd602283612542565b91506130c882613061565b604082019050919050565b600060208201905081810360008301526130ec816130b0565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b6000613129601d83612542565b9150613134826130f3565b602082019050919050565b600060208201905081810360008301526131588161311c565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b60006131bb602583612542565b91506131c68261315f565b604082019050919050565b600060208201905081810360008301526131ea816131ae565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b600061324d602383612542565b9150613258826131f1565b604082019050919050565b6000602082019050818103600083015261327c81613240565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006132df602683612542565b91506132ea82613283565b604082019050919050565b6000602082019050818103600083015261330e816132d2565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600061334b601f83612542565b915061335682613315565b602082019050919050565b6000602082019050818103600083015261337a8161333e565b9050919050565b60006060820190506133966000830186612891565b6133a36020830185612891565b6133b06040830184612676565b949350505050565b60006133c3826124a5565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036133f5576133f4612c00565b5b600182019050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000613441601783613400565b915061344c8261340b565b601782019050919050565b600061346282612537565b61346c8185613400565b935061347c818560208601612553565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006134be601183613400565b91506134c982613488565b601182019050919050565b60006134df82613434565b91506134eb8285613457565b91506134f6826134b1565b91506135028284613457565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000613544601483612542565b915061354f8261350e565b602082019050919050565b6000602082019050818103600083015261357381613537565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b60006135b0601083612542565b91506135bb8261357a565b602082019050919050565b600060208201905081810360008301526135df816135a3565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000613671602a83612542565b915061367c82613615565b604082019050919050565b600060208201905081810360008301526136a081613664565b9050919050565b60006136b2826124a5565b91506136bd836124a5565b92508282026136cb816124a5565b915082820484148315176136e2576136e1612c00565b5b5092915050565b60006136f4826124a5565b91506000820361370757613706612c00565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000613748602083612542565b915061375382613712565b602082019050919050565b600060208201905081810360008301526137778161373b565b9050919050565b6000613789826124a5565b9150613794836124a5565b92508282039050818111156137ac576137ab612c00565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a22989a3c73ef2895da365d02b7572bb6f24e425e460a1a2078ba8e18b66baf564736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/ERC20RecursiveRevertingPrecompileCall.sol b/contracts/solidity/ERC20RecursiveRevertingPrecompileCall.sol new file mode 100644 index 00000000..97c1355f --- /dev/null +++ b/contracts/solidity/ERC20RecursiveRevertingPrecompileCall.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.3.2 (token/ERC20/presets/ERC20PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; +import "./precompiles/distribution/DistributionI.sol" as distribution; +import "./precompiles/staking/StakingI.sol" as staking; +import "./precompiles/bech32/Bech32I.sol" as bech32; +import "./precompiles/common/Types.sol"; + +/** + * @dev {ERC20} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + */ +contract ERC20RecursiveRevertingPrecompileCall is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + uint8 private _decimals; + + event BeforeTokenTransferHookCalled(address from, address to, uint256 amount); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract and customizes tokens decimals + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol, uint8 decimals_) + ERC20(name, symbol) { + _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _grantRole(MINTER_ROLE, _msgSender()); + _grantRole(PAUSER_ROLE, _msgSender()); + _grantRole(BURNER_ROLE, _msgSender()); + _setupDecimals(decimals_); + } + + /** + * @dev Sets `_decimals` as `decimals_ once at Deployment' + */ + function _setupDecimals(uint8 decimals_) private { + _decimals = decimals_; + } + + /** + * @dev Overrides the `decimals()` method with custom `_decimals` + */ + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint"); + _mint(to, amount); + } + + /** + * @dev Destroys `amount` new tokens for `to`. + * + * See {ERC20-_burn}. + * + * Requirements: + * + * - the caller must have the `BURNER_ROLE`. + */ + function burnCoins(address from, uint256 amount) public virtual { + require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn"); + _burn(from, amount); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + // Emit an event to track if this hook is called + emit BeforeTokenTransferHookCalled(from, to, amount); + + for(uint256 i=0; i < 5; i++) { + try ERC20RecursiveRevertingPrecompileCall(address(this)).claimRewardsAndRevert() { + + } catch { + + } + + } + + super._beforeTokenTransfer(from, to, amount); + } + + function delegate( + string memory validatorAddress, + uint256 amount + ) external { + bool ok = staking.STAKING_CONTRACT.delegate(address(this), validatorAddress, amount); + require(ok, "failed to stake"); + } + + function claimRewardsAndRevert() public { + distribution.DISTRIBUTION_CONTRACT.claimRewards(address(this), 100); + revert(); + } +} \ No newline at end of file diff --git a/ethereum/eip712/encoding.go b/ethereum/eip712/encoding.go index 5292fa4e..98255f78 100644 --- a/ethereum/eip712/encoding.go +++ b/ethereum/eip712/encoding.go @@ -3,6 +3,7 @@ package eip712 import ( "errors" "fmt" + "strconv" apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes" @@ -100,9 +101,16 @@ func decodeAminoSignDoc(signDocBytes []byte) (apitypes.TypedData, error) { if err := validatePayloadMessages(msgs); err != nil { return apitypes.TypedData{}, err } - + // Extract the chain ID from the sign doc itself for EIP-712 domain + // This ensures we use the same chain ID that was used during signing + chainID := eip155ChainID + if aminoDoc.ChainID != "" { + if parsedChainID, err := parseChainID(aminoDoc.ChainID); err == nil { + chainID = parsedChainID + } + } typedData, err := WrapTxToTypedData( - eip155ChainID, + chainID, signDocBytes, ) if err != nil { @@ -175,9 +183,16 @@ func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) { msgs, body.Memo, ) - + // Extract the chain ID from the sign doc itself for EIP-712 domain + // This ensures we use the same chain ID that was used during signing + chainID := eip155ChainID + if signDoc.ChainId != "" { + if parsedChainID, err := parseChainID(signDoc.ChainId); err == nil { + chainID = parsedChainID + } + } typedData, err := WrapTxToTypedData( - eip155ChainID, + chainID, signBytes, ) if err != nil { @@ -187,6 +202,12 @@ func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) { return typedData, nil } +// parseChainID attempts to parse the chain ID string as a uint64. +// The chain ID in the sign doc should be the EIP-155 chain ID. +func parseChainID(chainIDStr string) (uint64, error) { + return strconv.ParseUint(chainIDStr, 10, 64) +} + // validateCodecInit ensures that both Amino and Protobuf encoding codecs have been set on app init, // so the module does not panic if either codec is not found. func validateCodecInit() error { diff --git a/evmd/precompiles.go b/evmd/precompiles.go index b8497776..1a71bf8c 100644 --- a/evmd/precompiles.go +++ b/evmd/precompiles.go @@ -101,13 +101,14 @@ func NewAvailableStaticPrecompiles( panic(fmt.Errorf("failed to instantiate bech32 precompile: %w", err)) } - stakingPrecompile, err := stakingprecompile.NewPrecompile(stakingKeeper, options.AddressCodec) + stakingPrecompile, err := stakingprecompile.NewPrecompile(stakingKeeper, bankKeeper, options.AddressCodec) if err != nil { panic(fmt.Errorf("failed to instantiate staking precompile: %w", err)) } distributionPrecompile, err := distprecompile.NewPrecompile( distributionKeeper, + bankKeeper, stakingKeeper, evmKeeper, options.AddressCodec, @@ -132,12 +133,12 @@ func NewAvailableStaticPrecompiles( panic(fmt.Errorf("failed to instantiate bank precompile: %w", err)) } - govPrecompile, err := govprecompile.NewPrecompile(govKeeper, codec, options.AddressCodec) + govPrecompile, err := govprecompile.NewPrecompile(govKeeper, bankKeeper, codec, options.AddressCodec) if err != nil { panic(fmt.Errorf("failed to instantiate gov precompile: %w", err)) } - slashingPrecompile, err := slashingprecompile.NewPrecompile(slashingKeeper, options.ValidatorAddrCodec, options.ConsensusAddrCodec) + slashingPrecompile, err := slashingprecompile.NewPrecompile(slashingKeeper, bankKeeper, options.ValidatorAddrCodec, options.ConsensusAddrCodec) if err != nil { panic(fmt.Errorf("failed to instantiate slashing precompile: %w", err)) } diff --git a/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go b/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go new file mode 100644 index 00000000..2cb3d58d --- /dev/null +++ b/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go @@ -0,0 +1,498 @@ +// Copied from https://github.com/cosmos/ibc-go/blob/7325bd2b00fd5e33d895770ec31b5be2f497d37a/modules/apps/transfer/transfer_test.go +// Why was this copied? +// This test suite was imported to validate that ExampleChain (an EVM-based chain) +// correctly supports IBC v1 token transfers using ibc-go’s Transfer module logic. +// The test ensures that ics20 precompile transfer (A → B) behave as expected across channels. +package ibc + +import ( + "fmt" + "math/big" + "testing" + + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/evm/utils" + + "github.com/cosmos/evm/contracts" + testutiltypes "github.com/cosmos/evm/testutil/types" + erc20types "github.com/cosmos/evm/x/erc20/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/evm/evmd" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/cosmos/evm/precompiles/ics20" + evmibctesting "github.com/cosmos/evm/testutil/ibc" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Test constants +const ( + // Token amounts + InitialTokenAmount = 1_000_000_000_000_000_000 // 1 token with 18 decimals + DelegationAmount = 1_000_000_000_000_000_000 // 1 token for delegation + RewardAmount = 100 // 100 base units for rewards + ExpectedRewards = "50.000000000000000000" // Expected reward amount after allocation + + // Test configuration + SenderIndex = 1 + TimeoutHeight = 110 +) + +// Test suite for ICS20 recursive precompile calls +// Tests the native balance handler bug where reverted distribution calls +// leave persistent bank events that are incorrectly aggregated + +type ICS20RecursivePrecompileCallsTestSuite struct { + suite.Suite + + coordinator *evmibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *evmibctesting.TestChain + chainAPrecompile *ics20.Precompile + chainB *evmibctesting.TestChain + chainBPrecompile *ics20.Precompile +} + +type stakingRewards struct { + Delegator sdk.AccAddress + Validator stakingtypes.Validator + RewardAmt sdkmath.Int +} + +func (suite *ICS20RecursivePrecompileCallsTestSuite) prepareStakingRewards(ctx sdk.Context, stkRs ...stakingRewards) (sdk.Context, error) { + for _, r := range stkRs { + // set distribution module account balance which pays out the rewards + bondDenom, err := suite.chainA.App.(*evmd.EVMD).StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + coins := sdk.NewCoins(sdk.NewCoin(bondDenom, r.RewardAmt)) + if err := suite.mintCoinsForDistrMod(ctx, coins); err != nil { + return ctx, err + } + + // allocate rewards to validator + allocatedRewards := sdk.NewDecCoins(sdk.NewDecCoin(bondDenom, r.RewardAmt)) + if err := suite.chainA.App.(*evmd.EVMD).GetDistrKeeper().AllocateTokensToValidator(ctx, r.Validator, allocatedRewards); err != nil { + return ctx, err + } + } + return ctx, nil +} + +func (suite *ICS20RecursivePrecompileCallsTestSuite) mintCoinsForDistrMod(ctx sdk.Context, amount sdk.Coins) error { + // Mint tokens for the distribution module to simulate fee accrued + if err := suite.chainA.App.(*evmd.EVMD).GetBankKeeper().MintCoins( + ctx, + minttypes.ModuleName, + amount, + ); err != nil { + return err + } + + return suite.chainA.App.(*evmd.EVMD).GetBankKeeper().SendCoinsFromModuleToModule( + ctx, + minttypes.ModuleName, + distrtypes.ModuleName, + amount, + ) +} + +// setupRevertingContractForTesting configures the contract for delegation and reward testing +func (suite *ICS20RecursivePrecompileCallsTestSuite) setupContractForTesting( + contractAddr common.Address, + contractData evmtypes.CompiledContract, + senderAcc evmibctesting.SenderAccount, +) { + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctxA := suite.chainA.GetContext() + senderAddr := senderAcc.SenderAccount.GetAddress() + senderEVMAddr := common.BytesToAddress(senderAddr.Bytes()) + deployerAddr := common.BytesToAddress(suite.chainA.SenderPrivKey.PubKey().Address().Bytes()) + + // Register ERC20 contract + _, err := evmAppA.Erc20Keeper.RegisterERC20(ctxA, &erc20types.MsgRegisterERC20{ + Signer: evmAppA.AccountKeeper.GetModuleAddress("gov").String(), + Erc20Addresses: []string{contractAddr.Hex()}, + }) + suite.Require().NoError(err, "registering ERC20 token should succeed") + suite.chainA.NextBlock() + + // Send native tokens to contract for delegation + bondDenom, err := evmAppA.StakingKeeper.BondDenom(ctxA) + suite.Require().NoError(err) + + contractAddrBech32, err := sdk.AccAddressFromHexUnsafe(contractAddr.Hex()[2:]) + suite.Require().NoError(err) + + deployerAddrBech32 := sdk.AccAddress(deployerAddr.Bytes()) + deployerBalance := evmAppA.BankKeeper.GetBalance(ctxA, deployerAddrBech32, bondDenom) + + // Send delegation amount to contract + sendAmount := sdkmath.NewInt(DelegationAmount) + if deployerBalance.Amount.LT(sendAmount) { + sendAmount = deployerBalance.Amount.Quo(sdkmath.NewInt(2)) + } + + err = evmAppA.BankKeeper.SendCoins( + ctxA, + deployerAddrBech32, + contractAddrBech32, + sdk.NewCoins(sdk.NewCoin(bondDenom, sendAmount)), + ) + suite.Require().NoError(err, "sending native tokens to contract should succeed") + + // Mint ERC20 tokens + _, err = evmAppA.GetEVMKeeper().CallEVM( + suite.chainA.GetContext(), + contractData.ABI, + deployerAddr, + contractAddr, + true, + nil, + "mint", + senderEVMAddr, + big.NewInt(InitialTokenAmount), + ) + suite.Require().NoError(err, "mint call failed") + suite.chainA.NextBlock() + + // Delegate tokens + vals, err := evmAppA.StakingKeeper.GetAllValidators(suite.chainA.GetContext()) + suite.Require().NoError(err) + + _, err = evmAppA.GetEVMKeeper().CallEVM( + ctxA, + contractData.ABI, + deployerAddr, + contractAddr, + true, + nil, + "delegate", + vals[0].OperatorAddress, + big.NewInt(DelegationAmount), + ) + suite.Require().NoError(err) + + // Verify delegation + valAddr, err := sdk.ValAddressFromBech32(vals[0].OperatorAddress) + suite.Require().NoError(err) + + amt, err := evmAppA.StakingKeeper.GetDelegation(suite.chainA.GetContext(), contractAddrBech32, valAddr) + suite.Require().NoError(err) + suite.Require().Equal(sendAmount.BigInt(), amt.Shares.BigInt()) + + // Setup rewards for testing + _, err = suite.prepareStakingRewards( + suite.chainA.GetContext(), + stakingRewards{ + Delegator: contractAddrBech32, + Validator: vals[0], + RewardAmt: sdkmath.NewInt(RewardAmount), + }, + ) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Verify minted balance + bal := evmAppA.GetErc20Keeper().BalanceOf(ctxA, contractData.ABI, contractAddr, common.BytesToAddress(senderAddr)) + suite.Require().Equal(big.NewInt(InitialTokenAmount), bal, "unexpected ERC20 balance") +} + +func (suite *ICS20RecursivePrecompileCallsTestSuite) SetupTest() { + suite.coordinator = evmibctesting.NewCoordinator(suite.T(), 2, 0, integration.SetupEvmd) + suite.chainA = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(1)) + suite.chainB = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(2)) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + suite.chainAPrecompile, _ = ics20.NewPrecompile( + evmAppA.BankKeeper, + *evmAppA.StakingKeeper, + evmAppA.TransferKeeper, + evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.EVMKeeper, + ) + bondDenom, err := evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + + evmAppA.Erc20Keeper.GetTokenPair(suite.chainA.GetContext(), evmAppA.Erc20Keeper.GetTokenPairID(suite.chainA.GetContext(), bondDenom)) + //evmAppA.Erc20Keeper.SetNativePrecompile(suite.chainA.GetContext(), werc20.Address()) + + avail := evmAppA.Erc20Keeper.IsNativePrecompileAvailable(suite.chainA.GetContext(), common.HexToAddress("0xD4949664cD82660AaE99bEdc034a0deA8A0bd517")) + suite.Require().True(avail) + + evmAppB := suite.chainB.App.(*evmd.EVMD) + suite.chainBPrecompile, _ = ics20.NewPrecompile( + evmAppB.BankKeeper, + *evmAppB.StakingKeeper, + evmAppB.TransferKeeper, + evmAppB.IBCKeeper.ChannelKeeper, + evmAppA.EVMKeeper, + ) +} + +// Constructs the following sends based on the established channels/connections +// 1 - from evmChainA to chainB +func (suite *ICS20RecursivePrecompileCallsTestSuite) TestHandleMsgTransfer() { + var ( + sourceDenomToTransfer string + msgAmount sdkmath.Int + err error + nativeErc20 *NativeErc20Info + erc20 bool + ) + + // originally a basic test case from the IBC testing package, and it has been added as-is to ensure that + // it still works properly when invoked through the ics20 precompile. + testCases := []struct { + name string + malleate func(senderAcc evmibctesting.SenderAccount) + postCheck func(querier distributionkeeper.Querier, valAddr string, eventAmount int) + }{ + { + "test recursive precompile call with reverts", + func(senderAcc evmibctesting.SenderAccount) { + // Deploy recursive ERC20 contract with _beforeTokenTransfer override + contractData, err := contracts.LoadERC20RecursiveReverting() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{"RecursiveRevertingToken", "RRCT", uint8(18)}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chainA, deploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + // Setup contract info and test parameters + nativeErc20 = &NativeErc20Info{ + ContractAddr: contractAddr, + ContractAbi: contractData.ABI, + Denom: "erc20:" + contractAddr.Hex(), + InitialBal: big.NewInt(InitialTokenAmount), + Account: common.BytesToAddress(senderAcc.SenderAccount.GetAddress().Bytes()), + } + + sourceDenomToTransfer = nativeErc20.Denom + msgAmount = sdkmath.NewIntFromBigInt(nativeErc20.InitialBal) + erc20 = true + + // Setup contract for testing + suite.setupContractForTesting(contractAddr, contractData, senderAcc) + }, + func(querier distributionkeeper.Querier, valAddr string, eventAmount int) { + evmAppA := suite.chainA.App.(*evmd.EVMD) + bondDenom, err := evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + contractBondDenomBalance := evmAppA.BankKeeper.GetBalance(suite.chainA.GetContext(), nativeErc20.ContractAddr.Bytes(), bondDenom) + suite.Require().Equal(contractBondDenomBalance.Amount, sdkmath.NewInt(0)) + // Check distribution rewards after transfer + afterRewards, err := querier.DelegationRewards(suite.chainA.GetContext(), &distrtypes.QueryDelegationRewardsRequest{ + DelegatorAddress: utils.Bech32StringFromHexAddress(nativeErc20.ContractAddr.String()), + ValidatorAddress: valAddr, + }) + suite.Require().NoError(err) + suite.Require().Equal(afterRewards.Rewards[0].Amount.String(), ExpectedRewards) + suite.Require().Equal(eventAmount, 21) + }, + }, + { + "test recursive precompile call without reverts", + func(senderAcc evmibctesting.SenderAccount) { + // Deploy recursive ERC20 contract with _beforeTokenTransfer override + contractData, err := contracts.LoadERC20RecursiveNonReverting() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{"RecursiveNonRevertingToken", "RNRCT", uint8(18)}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chainA, deploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + // Setup contract info and test parameters + nativeErc20 = &NativeErc20Info{ + ContractAddr: contractAddr, + ContractAbi: contractData.ABI, + Denom: "erc20:" + contractAddr.Hex(), + InitialBal: big.NewInt(InitialTokenAmount), + Account: common.BytesToAddress(senderAcc.SenderAccount.GetAddress().Bytes()), + } + + sourceDenomToTransfer = nativeErc20.Denom + msgAmount = sdkmath.NewIntFromBigInt(nativeErc20.InitialBal) + erc20 = true + + // Setup contract for testing + suite.setupContractForTesting(contractAddr, contractData, senderAcc) + }, + func(querier distributionkeeper.Querier, valAddr string, eventAmount int) { + evmAppA := suite.chainA.App.(*evmd.EVMD) + bondDenom, err := evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + contractBondDenomBalance := evmAppA.BankKeeper.GetBalance(suite.chainA.GetContext(), nativeErc20.ContractAddr.Bytes(), bondDenom) + + suite.Require().Equal(contractBondDenomBalance.Amount, sdkmath.NewInt(50)) + + // Check distribution rewards after transfer + afterRewards, err := querier.DelegationRewards(suite.chainA.GetContext(), &distrtypes.QueryDelegationRewardsRequest{ + DelegatorAddress: utils.Bech32StringFromHexAddress(nativeErc20.ContractAddr.String()), + ValidatorAddress: valAddr, + }) + suite.Require().NoError(err) + suite.Require().Nil(afterRewards.Rewards) + suite.Require().Equal(eventAmount, 30) // 20 base events + (1 successful reward claim + 1 send + 1 receive + 1 message + 1 transfer) + 4 empty reward claims + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + pathAToB := evmibctesting.NewTransferPath(suite.chainA, suite.chainB) + pathAToB.Setup() + traceAToB := transfertypes.NewHop(pathAToB.EndpointB.ChannelConfig.PortID, pathAToB.EndpointB.ChannelID) + + senderAccount := suite.chainA.SenderAccounts[SenderIndex] + senderAddr := senderAccount.SenderAccount.GetAddress() + + tc.malleate(senderAccount) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + + // Get balance helper function + GetBalance := func(addr sdk.AccAddress) sdk.Coin { + ctx := suite.chainA.GetContext() + if erc20 { + balanceAmt := evmAppA.Erc20Keeper.BalanceOf(ctx, nativeErc20.ContractAbi, nativeErc20.ContractAddr, nativeErc20.Account) + return sdk.Coin{ + Denom: nativeErc20.Denom, + Amount: sdkmath.NewIntFromBigInt(balanceAmt), + } + } + return evmAppA.BankKeeper.GetBalance(ctx, addr, sourceDenomToTransfer) + } + + // Verify initial state + senderBalance := GetBalance(nativeErc20.ContractAddr.Bytes()) + suite.Require().NoError(err) + bondDenom, err := evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + contractBondDenomBalance := evmAppA.BankKeeper.GetBalance(suite.chainA.GetContext(), nativeErc20.ContractAddr.Bytes(), bondDenom) + suite.Require().Equal(contractBondDenomBalance.Amount, sdkmath.NewInt(0)) + + // Setup transfer parameters + timeoutHeight := clienttypes.NewHeight(1, TimeoutHeight) + originalCoin := sdk.NewCoin(sourceDenomToTransfer, msgAmount) + + // Check distribution rewards before transfer + querier := distributionkeeper.NewQuerier(evmAppA.DistrKeeper) + vals, err := evmAppA.StakingKeeper.GetAllValidators(suite.chainA.GetContext()) + suite.Require().NoError(err) + + beforeRewards, err := querier.DelegationRewards(suite.chainA.GetContext(), &distrtypes.QueryDelegationRewardsRequest{ + DelegatorAddress: utils.Bech32StringFromHexAddress(nativeErc20.ContractAddr.String()), + ValidatorAddress: vals[0].OperatorAddress, + }) + suite.Require().NoError(err) + suite.Require().Equal(beforeRewards.Rewards[0].Amount.String(), ExpectedRewards) + + // Execute ICS20 transfer (this triggers the bug) + data, err := suite.chainAPrecompile.Pack("transfer", + pathAToB.EndpointA.ChannelConfig.PortID, + pathAToB.EndpointA.ChannelID, + originalCoin.Denom, + originalCoin.Amount.BigInt(), + common.BytesToAddress(senderAddr.Bytes()), // source addr should be evm hex addr + suite.chainB.SenderAccount.GetAddress().String(), // receiver should be cosmos bech32 addr + timeoutHeight, + uint64(0), + "", + ) + suite.Require().NoError(err) + + res, _, _, err := suite.chainA.SendEvmTx(senderAccount, SenderIndex, suite.chainAPrecompile.Address(), big.NewInt(0), data, 0) + suite.Require().NoError(err) // message committed + packet, err := evmibctesting.ParsePacketFromEvents(res.Events) + suite.Require().NoError(err) + + eventAmount := len(res.Events) + fmt.Println(res.Events) + + tc.postCheck(querier, vals[0].OperatorAddress, eventAmount) + + // Get the packet data to determine the amount of tokens being transferred (needed for sending entire balance) + packetData, err := transfertypes.UnmarshalPacketData(packet.GetData(), pathAToB.EndpointA.GetChannel().Version, "") + suite.Require().NoError(err) + transferAmount, ok := sdkmath.NewIntFromString(packetData.Token.Amount) + suite.Require().True(ok) + + afterSenderBalance := GetBalance(senderAddr) + suite.Require().Equal( + senderBalance.Amount.Sub(transferAmount).String(), + afterSenderBalance.Amount.String(), + ) + if msgAmount == transfertypes.UnboundedSpendLimit() { + suite.Require().Equal("0", afterSenderBalance.Amount.String(), "sender should have no balance left") + } + + relayerAddr := suite.chainA.SenderAccounts[0].SenderAccount.GetAddress() + relayerBalance := GetBalance(relayerAddr) + + // relay send + pathAToB.EndpointA.Chain.SenderAccount = evmAppA.AccountKeeper.GetAccount(suite.chainA.GetContext(), relayerAddr) //update account in the path as the sequence recorded in that object is out of date + err = pathAToB.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + feeAmt := evmibctesting.FeeCoins().AmountOf(sourceDenomToTransfer) + + // One for UpdateClient() and one for AcknowledgePacket() + relayPacketFeeAmt := feeAmt.Mul(sdkmath.NewInt(2)) + + afterRelayerBalance := GetBalance(relayerAddr) + suite.Require().Equal( + relayerBalance.Amount.Sub(relayPacketFeeAmt).String(), + afterRelayerBalance.Amount.String(), + ) + + escrowAddress := transfertypes.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) + + // check that module account escrow address has locked the tokens + chainAEscrowBalance := evmAppA.BankKeeper.GetBalance( + suite.chainA.GetContext(), + escrowAddress, + sourceDenomToTransfer, + ) + suite.Require().Equal(transferAmount.String(), chainAEscrowBalance.Amount.String()) + + // check that voucher exists on chain B + evmAppB := suite.chainB.App.(*evmd.EVMD) + chainBDenom := transfertypes.NewDenom(originalCoin.Denom, traceAToB) + chainBBalance := evmAppB.BankKeeper.GetBalance( + suite.chainB.GetContext(), + suite.chainB.SenderAccount.GetAddress(), + chainBDenom.IBCDenom(), + ) + coinSentFromAToB := sdk.NewCoin(chainBDenom.IBCDenom(), transferAmount) + suite.Require().Equal(coinSentFromAToB, chainBBalance) + }) + } +} + +func TestICS20RecursivePrecompileCallsTestSuite(t *testing.T) { + suite.Run(t, new(ICS20RecursivePrecompileCallsTestSuite)) +} diff --git a/evmd/tests/integration/balance_handler/balance_handler_test.go b/evmd/tests/integration/balance_handler/balance_handler_test.go new file mode 100644 index 00000000..1e7d07f9 --- /dev/null +++ b/evmd/tests/integration/balance_handler/balance_handler_test.go @@ -0,0 +1,106 @@ +package balancehandler + +import ( + "fmt" + + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/types" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/evm" + "github.com/cosmos/evm/contracts" + "github.com/cosmos/evm/evmd/tests/integration" + debugprecompile "github.com/cosmos/evm/evmd/tests/testdata/debug" + evmibctesting "github.com/cosmos/evm/testutil/ibc" + testutiltypes "github.com/cosmos/evm/testutil/types" +) + +// BalanceHandlerTestSuite tests the balance handler bug where recursive precompile calls +// share the same BalanceHandler instance, causing prevEventsLen to be overwritten. +// This leads to balance desync between native bank keeper and EVM stateDB. +type BalanceHandlerTestSuite struct { + suite.Suite + + coordinator *evmibctesting.Coordinator + chain *evmibctesting.TestChain +} + +func TestBalanceHandlerTestSuite(t *testing.T) { + suite.Run(t, new(BalanceHandlerTestSuite)) +} + +func (s *BalanceHandlerTestSuite) SetupTest() { + // Create coordinator with one chain + s.coordinator = evmibctesting.NewCoordinator(s.T(), 1, 0, integration.SetupEvmd) + s.chain = s.coordinator.GetChain(evmibctesting.GetEvmChainID(1)) +} + +// TestRecursivePrecompileCallsWithDebugPrecompile demonstrates the balance handler bug +// by triggering recursive calls that share the same BalanceHandler instance. +func (s *BalanceHandlerTestSuite) TestRecursivePrecompileCallsWithDebugPrecompile() { + evmApp := s.chain.App.(evm.EvmApp) + ctx := s.chain.GetContext() + + // Create and register debug precompile + debugPrec := debugprecompile.NewPrecompile(evmApp.GetBankKeeper(), evmApp.GetEVMKeeper()) + // Set the precompile directly in the EVM keeper's precompile map + evmApp.GetEVMKeeper().RegisterStaticPrecompile(debugPrec.Address(), debugPrec) + err := evmApp.GetEVMKeeper().EnableStaticPrecompiles(ctx, debugPrec.Address()) + s.Require().NoError(err) + + a, b, c := evmApp.GetEVMKeeper().GetPrecompileInstance(ctx, debugPrec.Address()) + fmt.Println(a, b, c) + + // Deploy caller contract + callerContract, err := contracts.LoadDebugPrecompileCaller() + s.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: callerContract, + ConstructorArgs: []interface{}{}, + } + + // Use local helper function + callerAddr, err := DeployContract(s.T(), s.chain, deploymentData) + s.Require().NoError(err) + s.chain.NextBlock() + + s.T().Logf("Deployed caller contract at %s", callerAddr.Hex()) + s.T().Logf("Debug precompile at %s", debugPrec.Address().Hex()) + + // Pack the input for callback(0) + input, err := callerContract.ABI.Pack("callback", big.NewInt(0)) + s.Require().NoError(err) + + // Fund Contract + err = evmApp.GetBankKeeper().SendCoins(ctx, s.chain.SenderAccounts[0].SenderAccount.GetAddress(), callerAddr.Bytes(), types.NewCoins(types.NewCoin("aatom", sdkmath.NewInt(10000000)))) + s.Require().NoError(err) + + res, _, _, err := s.chain.SendEvmTx( + s.chain.SenderAccounts[0], + 0, // sender index + callerAddr, // to address + big.NewInt(0), // value + input, // data + 0, // gas price multiplier + ) + s.Require().NoError(err, "callback transaction should succeed") + s.Require().False(res.IsErr(), "callback should not fail: %s", res.Events) + + s.Require().Equal(len(res.Events), 16, "callback should have 15 events") + debug_count := 0 + for _, event := range res.Events { + if event.Type == "debug_precompile" { + debug_count++ + } + } + s.Require().Equal(10, debug_count, "callback should have 1 debug precompile") + + // Advance to next block to finalize state + s.chain.NextBlock() +} diff --git a/evmd/tests/integration/balance_handler/helper.go b/evmd/tests/integration/balance_handler/helper.go new file mode 100644 index 00000000..85c6a0a6 --- /dev/null +++ b/evmd/tests/integration/balance_handler/helper.go @@ -0,0 +1,42 @@ +package balancehandler + +import ( + "errors" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + errorsmod "cosmossdk.io/errors" + + "github.com/cosmos/evm" + testutiltypes "github.com/cosmos/evm/testutil/types" + evmibctesting "github.com/cosmos/evm/testutil/ibc" +) + +// DeployContract deploys a contract to the test chain +func DeployContract(t *testing.T, chain *evmibctesting.TestChain, deploymentData testutiltypes.ContractDeploymentData) (common.Address, error) { + t.Helper() + + // Get account's nonce to create contract hash + from := common.BytesToAddress(chain.SenderPrivKey.PubKey().Address().Bytes()) + account := chain.App.(evm.EvmApp).GetEVMKeeper().GetAccount(chain.GetContext(), from) + if account == nil { + return common.Address{}, errors.New("account not found") + } + + ctorArgs, err := deploymentData.Contract.ABI.Pack("", deploymentData.ConstructorArgs...) + if err != nil { + return common.Address{}, errorsmod.Wrap(err, "failed to pack constructor arguments") + } + + data := deploymentData.Contract.Bin + data = append(data, ctorArgs...) + + _, err = chain.App.(evm.EvmApp).GetEVMKeeper().CallEVMWithData(chain.GetContext(), from, nil, data, true, nil) + if err != nil { + return common.Address{}, errorsmod.Wrapf(err, "failed to deploy contract") + } + + return crypto.CreateAddress(from, account.Nonce), nil +} diff --git a/evmd/tests/testdata/debug/debug.go b/evmd/tests/testdata/debug/debug.go new file mode 100644 index 00000000..a8d10ae9 --- /dev/null +++ b/evmd/tests/testdata/debug/debug.go @@ -0,0 +1,164 @@ +// Package debug defines test utilities that are meant for debugging the chain, and *not* for use in production. +package debug + +import ( + "cosmossdk.io/errors" + "fmt" + errors2 "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/evm/x/vm/statedb" + "github.com/ethereum/go-ethereum/core/tracing" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/vm" + + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + cmn "github.com/cosmos/evm/precompiles/common" +) + +// Precompile defines a debugging precompile for use in testing. +type Precompile struct { + cmn.Precompile + + evmKeeper EVMKeeper +} + +const DebugPrecompileAddress = "0x0000000000000000000000000000000000000799" + +func NewPrecompile(bankKeeper cmn.BankKeeper, evmKeeper EVMKeeper) *Precompile { + p := &Precompile{ + Precompile: cmn.Precompile{ + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + BalanceHandlerFactory: cmn.NewBalanceHandlerFactory(bankKeeper), + }, + evmKeeper: evmKeeper, + } + // SetAddress defines the address of the distribution compile contract. + p.SetAddress(common.HexToAddress(DebugPrecompileAddress)) + return p +} + +func (p Precompile) RequiredGas(input []byte) uint64 { + return 1000 +} + +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + stateDB, ok := evm.StateDB.(*statedb.StateDB) + if !ok { + return nil, errors.Wrap(errors2.ErrUnauthorized, "could not create statedb in debug precompile") + } + + // get the stateDB cache ctx + ctx, err := stateDB.GetCacheContext() + if err != nil { + return nil, err + } + + // take a snapshot of the current state before any changes + // to be able to revert the changes + snapshot := stateDB.MultiStoreSnapshot() + events := ctx.EventManager().Events() + + // add precompileCall entry on the stateDB journal + // this allows to revert the changes within an evm tx + err = stateDB.AddPrecompileFn(p.Address(), snapshot, events) + if err != nil { + return nil, err + } + + // commit the current changes in the cache ctx + // to get the updated state for the precompile call + if err := stateDB.CommitWithCacheCtx(); err != nil { + return nil, err + } + + // Start the balance change handler before executing the precompile. + var balanceHandler *cmn.BalanceHandler + if p.BalanceHandlerFactory != nil { + balanceHandler = p.BalanceHandlerFactory.NewBalanceHandler() + } + + if balanceHandler != nil { + balanceHandler.BeforeBalanceChange(ctx) + } + + initialGas := ctx.GasMeter().GasConsumed() + + // set the default SDK gas configuration to track gas usage + // we are changing the gas meter type, so it panics gracefully when out of gas + ctx = ctx.WithGasMeter(storetypes.NewGasMeter(contract.Gas)). + WithKVGasConfig(p.KvGasConfig). + WithTransientKVGasConfig(p.TransientKVGasConfig) + // we need to consume the gas that was already used by the EVM + ctx.GasMeter().ConsumeGas(initialGas, "creating a new gas meter") + + // This handles any out of gas errors that may occur during the execution of a precompile tx or query. + // It avoids panics and returns the out of gas error so the EVM can continue gracefully. + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + res, err := p.Execute(ctx, stateDB, contract, readonly) + if err != nil { + return nil, err + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + // Process the native balance changes after the method execution. + if balanceHandler != nil { + if err := balanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } + } + + return res, nil +} + +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + switch contract.Input[0] { + case 0: // callback() + return p.Call0(ctx, stateDB, contract, readOnly) + case 1: // call1() + return p.Call1(ctx, stateDB, contract, readOnly) + } + return nil, fmt.Errorf("unknown method: %x", contract.Input[0]) +} + +func (p Precompile) Call0(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + // data := crypto.Keccak256([]byte("function callback()"))[:4] + counter := new(big.Int).SetBytes(contract.Input[1:]) + counter = new(big.Int).Add(counter, big.NewInt(1)) + + args := math.U256Bytes(counter) + selector := []byte{0xff, 0x58, 0x5c, 0xaf} + data := append(selector, args...) + + caller := contract.Caller() + fmt.Printf("Execute debug precompile %s, %p\n", caller.String(), p.BalanceHandlerFactory) + rsp, err := p.evmKeeper.CallEVMWithData(ctx, p.Address(), &caller, data, true, nil) + fmt.Println("callback response:", rsp.Ret, err) + if err != nil { + return nil, err + } + return nil, nil +} + +func (p Precompile) Call1(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + "debug_precompile", + sdk.NewAttribute("address", p.Address().String()), + ), + ) + return nil, nil +} diff --git a/evmd/tests/testdata/debug/interface.go b/evmd/tests/testdata/debug/interface.go new file mode 100644 index 00000000..2fc70e75 --- /dev/null +++ b/evmd/tests/testdata/debug/interface.go @@ -0,0 +1,21 @@ +package debug + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "math/big" +) + +type EVMKeeper interface { + CallEVM(ctx sdk.Context, abi abi.ABI, from, contract common.Address, commit bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) + CallEVMWithData( + ctx sdk.Context, + from common.Address, + contract *common.Address, + data []byte, + commit bool, + gasCap *big.Int, + ) (*evmtypes.MsgEthereumTxResponse, error) +} diff --git a/precompiles/common/balance_handler.go b/precompiles/common/balance_handler.go index 6f48bbe8..cc056934 100644 --- a/precompiles/common/balance_handler.go +++ b/precompiles/common/balance_handler.go @@ -15,18 +15,31 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -// BalanceHandler is a struct that handles balance changes in the Cosmos SDK context. -type BalanceHandler struct { - prevEventsLen int +// BalanceHandlerFactory is a factory struct to create BalanceHandler instances. +type BalanceHandlerFactory struct { + bankKeeper BankKeeper } // NewBalanceHandler creates a new BalanceHandler instance. -func NewBalanceHandler() *BalanceHandler { +func NewBalanceHandlerFactory(bankKeeper BankKeeper) *BalanceHandlerFactory { + return &BalanceHandlerFactory{ + bankKeeper: bankKeeper, + } +} + +func (bhf BalanceHandlerFactory) NewBalanceHandler() *BalanceHandler { return &BalanceHandler{ + bankKeeper: bhf.bankKeeper, prevEventsLen: 0, } } +// BalanceHandler is a struct that handles balance changes in the Cosmos SDK context. +type BalanceHandler struct { + bankKeeper BankKeeper + prevEventsLen int +} + // BeforeBalanceChange is called before any balance changes by precompile methods. // It records the current number of events in the context to later process balance changes // using the recorded events. diff --git a/precompiles/common/balance_handler_test.go b/precompiles/common/balance_handler_test.go index d9e94b35..3946e757 100644 --- a/precompiles/common/balance_handler_test.go +++ b/precompiles/common/balance_handler_test.go @@ -167,7 +167,8 @@ func TestAfterBalanceChange(t *testing.T) { // initial balance for spender stateDB.AddBalance(spender, uint256.NewInt(5), tracing.BalanceChangeUnspecified) - bh := NewBalanceHandler() + bfh := NewBalanceHandlerFactory(mocks.NewBankKeeper(t)) + bh := bfh.NewBalanceHandler() bh.BeforeBalanceChange(ctx) coins := sdk.NewCoins(sdk.NewInt64Coin(evmtypes.GetEVMCoinDenom(), 3)) @@ -195,7 +196,8 @@ func TestAfterBalanceChangeErrors(t *testing.T) { require.NoError(t, err) addr := addrs[0] - bh := NewBalanceHandler() + bfh := NewBalanceHandlerFactory(mocks.NewBankKeeper(t)) + bh := bfh.NewBalanceHandler() bh.BeforeBalanceChange(ctx) // invalid address in event diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index 0ea006fd..9def99b0 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -20,10 +20,10 @@ import ( // precompile needs to run which includes the ABI, Gas config. type Precompile struct { abi.ABI - KvGasConfig storetypes.GasConfig - TransientKVGasConfig storetypes.GasConfig - address common.Address - balanceHandler *BalanceHandler + KvGasConfig storetypes.GasConfig + TransientKVGasConfig storetypes.GasConfig + address common.Address + BalanceHandlerFactory *BalanceHandlerFactory } // Operation is a type that defines if the precompile call @@ -224,10 +224,3 @@ func (p Precompile) standardCallData(contract *vm.Contract) (method *abi.Method, return method, nil } - -func (p *Precompile) GetBalanceHandler() *BalanceHandler { - if p.balanceHandler == nil { - p.balanceHandler = NewBalanceHandler() - } - return p.balanceHandler -} diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index 2c0f235a..ce53280d 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -40,6 +40,7 @@ type Precompile struct { // PrecompiledContract interface. func NewPrecompile( distributionKeeper distributionkeeper.Keeper, + bankKeeper cmn.BankKeeper, stakingKeeper stakingkeeper.Keeper, evmKeeper *evmkeeper.Keeper, addrCdc address.Codec, @@ -51,9 +52,10 @@ func NewPrecompile( p := &Precompile{ Precompile: cmn.Precompile{ - ABI: newAbi, - KvGasConfig: storetypes.KVGasConfig(), - TransientKVGasConfig: storetypes.TransientGasConfig(), + ABI: newAbi, + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + BalanceHandlerFactory: cmn.NewBalanceHandlerFactory(bankKeeper), }, stakingKeeper: stakingKeeper, distributionKeeper: distributionKeeper, @@ -104,7 +106,14 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) + var balanceHandler *cmn.BalanceHandler + if p.BalanceHandlerFactory != nil { + balanceHandler = p.BalanceHandlerFactory.NewBalanceHandler() + } + + if balanceHandler != nil { + balanceHandler.BeforeBalanceChange(ctx) + } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. @@ -157,8 +166,10 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err + if balanceHandler != nil { + if err := balanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } } return bz, nil diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index a7a5506b..7b20a28b 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -46,6 +46,7 @@ func LoadABI() (abi.ABI, error) { // PrecompiledContract interface. func NewPrecompile( govKeeper govkeeper.Keeper, + bankKeeper cmn.BankKeeper, codec codec.Codec, addrCdc address.Codec, ) (*Precompile, error) { @@ -56,9 +57,10 @@ func NewPrecompile( p := &Precompile{ Precompile: cmn.Precompile{ - ABI: abi, - KvGasConfig: storetypes.KVGasConfig(), - TransientKVGasConfig: storetypes.TransientGasConfig(), + ABI: abi, + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + BalanceHandlerFactory: cmn.NewBalanceHandlerFactory(bankKeeper), }, govKeeper: govKeeper, codec: codec, @@ -105,7 +107,14 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) + var balanceHandler *cmn.BalanceHandler + if p.BalanceHandlerFactory != nil { + balanceHandler = p.BalanceHandlerFactory.NewBalanceHandler() + } + + if balanceHandler != nil { + balanceHandler.BeforeBalanceChange(ctx) + } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. @@ -158,9 +167,10 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Process the native balance changes after the method execution. - err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB) - if err != nil { - return nil, err + if balanceHandler != nil { + if err := balanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } } return bz, nil diff --git a/precompiles/ics20/ics20.go b/precompiles/ics20/ics20.go index 88d840a0..035c3ed5 100644 --- a/precompiles/ics20/ics20.go +++ b/precompiles/ics20/ics20.go @@ -55,9 +55,10 @@ func NewPrecompile( p := &Precompile{ Precompile: cmn.Precompile{ - ABI: newAbi, - KvGasConfig: storetypes.KVGasConfig(), - TransientKVGasConfig: storetypes.TransientGasConfig(), + ABI: newAbi, + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + BalanceHandlerFactory: cmn.NewBalanceHandlerFactory(bankKeeper), }, bankKeeper: bankKeeper, transferKeeper: transferKeeper, @@ -107,7 +108,14 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) + var balanceHandler *cmn.BalanceHandler + if p.BalanceHandlerFactory != nil { + balanceHandler = p.BalanceHandlerFactory.NewBalanceHandler() + } + + if balanceHandler != nil { + balanceHandler.BeforeBalanceChange(ctx) + } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. @@ -139,8 +147,10 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err + if balanceHandler != nil { + if err := balanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } } return bz, nil diff --git a/precompiles/slashing/slashing.go b/precompiles/slashing/slashing.go index 2bd268c5..442af163 100644 --- a/precompiles/slashing/slashing.go +++ b/precompiles/slashing/slashing.go @@ -46,6 +46,7 @@ func LoadABI() (abi.ABI, error) { // PrecompiledContract interface. func NewPrecompile( slashingKeeper slashingkeeper.Keeper, + bankKeeper cmn.BankKeeper, valCdc, consCdc address.Codec, ) (*Precompile, error) { abi, err := LoadABI() @@ -55,9 +56,10 @@ func NewPrecompile( p := &Precompile{ Precompile: cmn.Precompile{ - ABI: abi, - KvGasConfig: storetypes.KVGasConfig(), - TransientKVGasConfig: storetypes.TransientGasConfig(), + ABI: abi, + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + BalanceHandlerFactory: cmn.NewBalanceHandlerFactory(bankKeeper), }, slashingKeeper: slashingKeeper, valCodec: valCdc, @@ -104,7 +106,14 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) + var balanceHandler *cmn.BalanceHandler + if p.BalanceHandlerFactory != nil { + balanceHandler = p.BalanceHandlerFactory.NewBalanceHandler() + } + + if balanceHandler != nil { + balanceHandler.BeforeBalanceChange(ctx) + } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. @@ -136,8 +145,10 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Process the native balance changes after the method execution. - if err := p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err + if balanceHandler != nil { + if err := balanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } } return bz, nil diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index cb4d2904..e2385b9f 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -43,6 +43,7 @@ func LoadABI() (abi.ABI, error) { // PrecompiledContract interface. func NewPrecompile( stakingKeeper stakingkeeper.Keeper, + bankKeeper cmn.BankKeeper, addrCdc address.Codec, ) (*Precompile, error) { abi, err := LoadABI() @@ -52,9 +53,10 @@ func NewPrecompile( p := &Precompile{ Precompile: cmn.Precompile{ - ABI: abi, - KvGasConfig: storetypes.KVGasConfig(), - TransientKVGasConfig: storetypes.TransientGasConfig(), + ABI: abi, + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + BalanceHandlerFactory: cmn.NewBalanceHandlerFactory(bankKeeper), }, stakingKeeper: stakingKeeper, addrCdc: addrCdc, @@ -99,7 +101,14 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) + var balanceHandler *cmn.BalanceHandler + if p.BalanceHandlerFactory != nil { + balanceHandler = p.BalanceHandlerFactory.NewBalanceHandler() + } + + if balanceHandler != nil { + balanceHandler.BeforeBalanceChange(ctx) + } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. @@ -145,8 +154,10 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err + if balanceHandler != nil { + if err := balanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } } return bz, nil diff --git a/tests/integration/precompiles/distribution/test_setup.go b/tests/integration/precompiles/distribution/test_setup.go index 2fe56f43..569d0cc1 100644 --- a/tests/integration/precompiles/distribution/test_setup.go +++ b/tests/integration/precompiles/distribution/test_setup.go @@ -131,6 +131,7 @@ func (s *PrecompileTestSuite) SetupTest() { s.network = nw s.precompile, err = distribution.NewPrecompile( s.network.App.GetDistrKeeper(), + s.network.App.GetBankKeeper(), *s.network.App.GetStakingKeeper(), s.network.App.GetEVMKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), diff --git a/tests/integration/precompiles/distribution/test_utils.go b/tests/integration/precompiles/distribution/test_utils.go index fe252380..d5f03c6a 100644 --- a/tests/integration/precompiles/distribution/test_utils.go +++ b/tests/integration/precompiles/distribution/test_utils.go @@ -84,6 +84,7 @@ func (s *PrecompileTestSuite) fundAccountWithBaseDenom(ctx sdk.Context, addr sdk func (s *PrecompileTestSuite) getStakingPrecompile() (*staking.Precompile, error) { return staking.NewPrecompile( *s.network.App.GetStakingKeeper(), + s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), ) } diff --git a/tests/integration/precompiles/gov/test_setup.go b/tests/integration/precompiles/gov/test_setup.go index 4e7ec6ee..1c71b3f4 100644 --- a/tests/integration/precompiles/gov/test_setup.go +++ b/tests/integration/precompiles/gov/test_setup.go @@ -138,6 +138,7 @@ func (s *PrecompileTestSuite) SetupTest() { if s.precompile, err = gov.NewPrecompile( s.network.App.GetGovKeeper(), + s.network.App.GetBankKeeper(), s.network.App.AppCodec(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), ); err != nil { diff --git a/tests/integration/precompiles/slashing/test_setup.go b/tests/integration/precompiles/slashing/test_setup.go index f64ee11a..7558a34f 100644 --- a/tests/integration/precompiles/slashing/test_setup.go +++ b/tests/integration/precompiles/slashing/test_setup.go @@ -56,6 +56,7 @@ func (s *PrecompileTestSuite) SetupTest() { if s.precompile, err = slashing.NewPrecompile( s.network.App.GetSlashingKeeper(), + s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), address.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), ); err != nil { diff --git a/tests/integration/precompiles/staking/test_setup.go b/tests/integration/precompiles/staking/test_setup.go index c20d7d42..2e7aedfa 100644 --- a/tests/integration/precompiles/staking/test_setup.go +++ b/tests/integration/precompiles/staking/test_setup.go @@ -82,6 +82,7 @@ func (s *PrecompileTestSuite) SetupTest() { if s.precompile, err = staking.NewPrecompile( *s.network.App.GetStakingKeeper(), + s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), ); err != nil { panic(err) diff --git a/wallets/usbwallet/hub.go b/wallets/usbwallet/hub.go index 897ab9f4..2d0406bd 100644 --- a/wallets/usbwallet/hub.go +++ b/wallets/usbwallet/hub.go @@ -156,7 +156,11 @@ func (hub *Hub) refreshWallets() { for _, info := range infos { for _, id := range hub.productIDs { // Windows and macOS use UsageID matching, Linux uses Interface matching - if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { + // Ledger product IDs use MMII format where MM is device model and II is interface flags. + // Match either exact legacy IDs (0x0001, 0x0004, etc.) or device model prefix for + // WebUSB/app-specific IDs (e.g., 0x4011 matches 0x4000 prefix for Nano X with Ethereum app). + modelMatch := id >= 0x1000 && (info.ProductID>>8 == id>>8) + if (info.ProductID == id || modelMatch) && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { devices = append(devices, info) break } diff --git a/x/vm/keeper/static_precompiles.go b/x/vm/keeper/static_precompiles.go index bece0888..1ceb11cb 100644 --- a/x/vm/keeper/static_precompiles.go +++ b/x/vm/keeper/static_precompiles.go @@ -24,6 +24,14 @@ func (k *Keeper) WithStaticPrecompiles(precompiles map[common.Address]vm.Precomp return k } +// WithStaticPrecompiles sets the available static precompiled contracts. +func (k *Keeper) RegisterStaticPrecompile(address common.Address, precompile vm.PrecompiledContract) { + if k.precompiles == nil { + k.precompiles = make(map[common.Address]vm.PrecompiledContract) + } + k.precompiles[address] = precompile +} + // GetStaticPrecompileInstance returns the instance of the given static precompile address. func (k *Keeper) GetStaticPrecompileInstance(params *types.Params, address common.Address) (vm.PrecompiledContract, bool, error) { if k.IsAvailableStaticPrecompile(params, address) { diff --git a/x/vm/statedb/statedb.go b/x/vm/statedb/statedb.go index cce997d6..dc91c7c1 100644 --- a/x/vm/statedb/statedb.go +++ b/x/vm/statedb/statedb.go @@ -34,6 +34,7 @@ import ( type revision struct { id int journalIndex int + events sdk.Events } var _ vm.StateDB = &StateDB{} @@ -641,7 +642,7 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre func (s *StateDB) Snapshot() int { id := s.nextRevisionID s.nextRevisionID++ - s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()}) + s.validRevisions = append(s.validRevisions, revision{id, s.journal.length(), s.ctx.EventManager().Events()}) return id } @@ -656,6 +657,11 @@ func (s *StateDB) RevertToSnapshot(revid int) { } snapshot := s.validRevisions[idx].journalIndex + // revert back to snapshotted events + eventManager := sdk.NewEventManager() + eventManager.EmitEvents(s.validRevisions[idx].events) + s.ctx = s.ctx.WithEventManager(eventManager) + // Replay the journal to undo changes and remove invalidated snapshots s.journal.Revert(s, snapshot) s.validRevisions = s.validRevisions[:idx] diff --git a/x/vm/statedb/statedb_test.go b/x/vm/statedb/statedb_test.go index 07b54bf1..61ee34b5 100644 --- a/x/vm/statedb/statedb_test.go +++ b/x/vm/statedb/statedb_test.go @@ -192,7 +192,7 @@ func (suite *StateDBTestSuite) TestAccount() { } for _, tc := range testCases { suite.Run(tc.name, func() { - ctx := sdk.Context{} + ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) tc.malleate(ctx, db) @@ -266,7 +266,7 @@ func (suite *StateDBTestSuite) TestBalance() { for _, tc := range testCases { suite.Run(tc.name, func() { - ctx := sdk.Context{} + ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) tc.malleate(db) @@ -321,7 +321,7 @@ func (suite *StateDBTestSuite) TestState() { for _, tc := range testCases { suite.Run(tc.name, func() { - ctx := sdk.Context{} + ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) tc.malleate(db) @@ -431,7 +431,7 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { } for _, tc := range testCases { suite.Run(tc.name, func() { - ctx := sdk.Context{} + ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() { @@ -470,7 +470,7 @@ func (suite *StateDBTestSuite) TestNestedSnapshot() { value1 := common.BigToHash(big.NewInt(1)) value2 := common.BigToHash(big.NewInt(2)) - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), emptyTxConfig) rev1 := db.Snapshot() db.SetState(address, key, value1) @@ -656,7 +656,7 @@ func (suite *StateDBTestSuite) TestRefund() { } func (suite *StateDBTestSuite) TestIterateStorage() { - ctx := sdk.Context{} + ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(2))