diff --git a/CHANGELOG.md b/CHANGELOG.md index 78a5f03d8..60a0cb7d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - [\#589](https://github.com/cosmos/evm/pull/589) Remove parallelization blockers via migration from transient to object store, refactoring of gas, indexing, and bloom utilities. - [\#768](https://github.com/cosmos/evm/pull/768) Added ICS-02 Client Router precompile +- [\#804](https://github.com/cosmos/evm/pull/804) Bank precompile redesign. ### BUG FIXES diff --git a/Makefile b/Makefile index 0c84679bc..45bb16bee 100644 --- a/Makefile +++ b/Makefile @@ -168,7 +168,7 @@ test-unit-cover: run-tests @echo "๐Ÿ”€ Merging evmd coverage into root coverage..." @tail -n +2 evmd/coverage_evmd.txt >> coverage.txt && rm evmd/coverage_evmd.txt @echo "๐Ÿงน Filtering ignored files from coverage.txt..." - @grep -v -E '/cmd/|/client/|/proto/|/testutil/|/mocks/|/test_.*\.go:|\.pb\.go:|\.pb\.gw\.go:|/x/[^/]+/module\.go:|/scripts/|/ibc/testing/|/version/|\.md:|\.pulsar\.go:' coverage.txt > tmp_coverage.txt && mv tmp_coverage.txt coverage.txt + @grep -v -E '/cmd/|/client/|/proto/|/testutil/|/mocks/|/test_.*\.go:|\.pb\.go:|\.pb\.gw\.go:|\.abi\.go:|/x/[^/]+/module\.go:|/scripts/|/ibc/testing/|/version/|\.md:|\.pulsar\.go:' coverage.txt > tmp_coverage.txt && mv tmp_coverage.txt coverage.txt test: test-unit diff --git a/evmd/app.go b/evmd/app.go index a4bfe0be1..dcb0500ba 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -462,6 +462,7 @@ func NewExampleApp( *app.StakingKeeper, app.DistrKeeper, app.PreciseBankKeeper, + app.BankKeeper, &app.Erc20Keeper, &app.TransferKeeper, app.IBCKeeper.ChannelKeeper, diff --git a/evmd/go.mod b/evmd/go.mod index 3df843653..e6b4d304f 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -20,7 +20,7 @@ require ( github.com/cosmos/evm v0.2.0 github.com/cosmos/gogoproto v1.7.2 github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20251027215440-22f0033d0aee - github.com/ethereum/go-ethereum v1.16.5 + github.com/ethereum/go-ethereum v1.16.7 github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.38.0 github.com/spf13/cast v1.10.0 @@ -242,6 +242,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yihuang/go-abi v0.1.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect diff --git a/evmd/go.sum b/evmd/go.sum index aedd18606..3363a33f1 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -972,6 +972,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -1002,6 +1004,8 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yihuang/go-abi v0.1.1 h1:5MHV/wOz0wywsb9IhaZmHLhBNAF5EzSXisPyv3gN5Rs= +github.com/yihuang/go-abi v0.1.1/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/go.mod b/go.mod index 312f4b7eb..ff34c71d5 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/cosmos/ledger-cosmos-go v0.16.0 github.com/creachadair/tomledit v0.0.28 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc - github.com/ethereum/go-ethereum v1.16.5 + github.com/ethereum/go-ethereum v1.16.7 github.com/gogo/protobuf v1.3.2 github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 @@ -46,6 +46,7 @@ require ( github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 github.com/tyler-smith/go-bip39 v1.1.0 + github.com/yihuang/go-abi v0.1.1 github.com/zondax/hid v0.9.2 go.uber.org/mock v0.6.0 golang.org/x/crypto v0.45.0 @@ -266,6 +267,7 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.21.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/oauth2 v0.31.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/term v0.37.0 // indirect diff --git a/go.sum b/go.sum index ece2e2572..974da6a1e 100644 --- a/go.sum +++ b/go.sum @@ -952,6 +952,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -982,6 +984,8 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yihuang/go-abi v0.1.1 h1:5MHV/wOz0wywsb9IhaZmHLhBNAF5EzSXisPyv3gN5Rs= +github.com/yihuang/go-abi v0.1.1/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -1089,6 +1093,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/precompiles/bank/ERC20.bin b/precompiles/bank/ERC20.bin new file mode 100644 index 000000000..26ab0e612 --- /dev/null +++ b/precompiles/bank/ERC20.bin @@ -0,0 +1 @@ +60a0604052346102315761107d8038038061001981610235565b9283398101906040818303126102315780516001600160401b0381116102315781019082601f830112156102315781516001600160401b03811161021d5761006a601f8201601f1916602001610235565b9381855260208285010111610231576020815f92828096018388015e8501015201516001600160a01b03811681036102315781516001600160401b03811161021d575f54600181811c91168015610213575b60208210146101ff57601f811161019d575b50602092601f821160011461013e57928192935f92610133575b50508160011b915f199060031b1c1916175f555b608052604051610e22908161025b823960805181818161030a015281816103c10152818161048e0152818161057f0152610c660152f35b015190505f806100e8565b601f198216935f8052805f20915f5b868110610185575083600195961061016d575b505050811b015f556100fc565b01515f1960f88460031b161c191690555f8080610160565b9192602060018192868501518155019401920161014d565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c810191602084106101f5575b601f0160051c01905b8181106101ea57506100ce565b5f81556001016101dd565b90915081906101d4565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100bc565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761021d5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146108a557508063095ea7b3146107f857806318160ddd1461078d57806323b872dd146105f9578063313ce567146104fb57806370a08231146103e557806376cdb03b1461037757806395d89b4114610287578063a9059cbb14610238578063c370b042146101255763dd62ed3e14610095575f80fd5b346101215760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610121576100cc610954565b73ffffffffffffffffffffffffffffffffffffffff6100e9610977565b91165f52600160205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b5f80fd5b34610121575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610121576040515f5f546101628161099a565b80845290600181169081156101f6575060011461019a575b6101968361018a818503826109eb565b6040519182918261090c565b0390f35b5f8080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b8082106101dc5750909150810160200161018a61017a565b9192600181602092548385880101520191019092916101c4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b8401909101915061018a905061017a565b346101215760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101215761027c610272610954565b6024359033610ba5565b602060405160018152f35b34610121575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610121576040517f41bb0559000000000000000000000000000000000000000000000000000000008152602060048201525f81806102f160248201610aea565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa801561036c57610196915f9161034a575b506040519182918261090c565b61036691503d805f833e61035e81836109eb565b810190610a59565b8261033d565b6040513d5f823e3d90fd5b34610121575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101215760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101215761041c610954565b73ffffffffffffffffffffffffffffffffffffffff604051917fb9b092c8000000000000000000000000000000000000000000000000000000008352166004820152604060248201526020818061047560448201610aea565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa801561036c575f906104c8575b602090604051908152f35b506020813d6020116104f3575b816104e2602093836109eb565b8101031261012157602090516104bd565b3d91506104d5565b34610121575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610121576040517f3b2b3204000000000000000000000000000000000000000000000000000000008152602060048201526020818061056660248201610aea565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa801561036c575f906105bc575b60209060ff60405191168152f35b506020813d6020116105f1575b816105d6602093836109eb565b81010312610121575160ff81168103610121576020906105ae565b3d91506105c9565b346101215760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012157610630610954565b610638610977565b6044359073ffffffffffffffffffffffffffffffffffffffff831692835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106106b4575b5061027c9350610ba5565b83811061075957841561072d5733156107015761027c945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f2091039055846106a9565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b34610121575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610121576040517fc415db13000000000000000000000000000000000000000000000000000000008152602060048201526020818061047560248201610aea565b346101215760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101215761082f610954565b60243590331561072d5773ffffffffffffffffffffffffffffffffffffffff1690811561070157335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610121575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610121577f5b43bc99000000000000000000000000000000000000000000000000000000008152602060048201525f81806102f160248201610aea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361012157565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361012157565b90600182811c921680156109e1575b60208310146109b457565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916109a9565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610a2c57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6020818303126101215780519067ffffffffffffffff8211610121570181601f820112156101215780519067ffffffffffffffff8211610a2c5760405192610ac960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601856109eb565b8284526020838301011161012157815f9260208093018386015e8301015290565b905f915f5490610af98261099a565b8082529160018116908115610b6b5750600114610b14575050565b5f8080529293509091907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b838310610b51575060209250010190565b600181602092949394548385870101520191019190610b40565b60209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091509291921683830152151560051b010190565b73ffffffffffffffffffffffffffffffffffffffff16908115610dc05773ffffffffffffffffffffffffffffffffffffffff16918215610d94576040517f1af716ba000000000000000000000000000000000000000000000000000000008152826004820152836024820152816044820152608060648201525f815f54610c2b8161099a565b908160848401526001811690815f14610d545750600114610cfc575b508060209203815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1801561036c57610cc1575b5060207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91604051908152a3565b6020813d602011610cf4575b81610cda602093836109eb565b810103126101215751801515810361012157506020610c93565b3d9150610ccd565b5f8080529192507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b818310610d3a575050810160a4019080610c47565b805483860160a40152849350602090920191600101610d25565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660a48085019190915291151560051b83019091019250819050610c47565b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffdfea26469706673582212209877ef265ed97e48971f94b7bbf60b6475123ef4a1b88d7af8ae4a8f4526564f64736f6c634300081e0033 \ No newline at end of file diff --git a/precompiles/bank/ERC20.sol b/precompiles/bank/ERC20.sol new file mode 100644 index 000000000..9df5e6d22 --- /dev/null +++ b/precompiles/bank/ERC20.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IBankPrecompile { + // queries + function name(string memory denom) external view returns (string memory); + function symbol(string memory denom) external view returns (string memory); + function decimals(string memory denom) external view returns (uint8); + function totalSupply(string memory denom) external view returns (uint256); + function balanceOf(address account, string memory denom) external view returns (uint256); + + function transferFrom(address from, address to, uint256 value, string memory denom) external returns (bool); +} + +contract ERC20 { + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + error ERC20InvalidSender(address sender); + error ERC20InvalidReceiver(address receiver); + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + error ERC20InvalidApprover(address approver); + error ERC20InvalidSpender(address spender); + + + string public denom; + mapping(address account => mapping(address spender => uint256)) public allowance; + + IBankPrecompile public immutable bank; + + constructor(string memory denom_, IBankPrecompile bank_) { + denom = denom_; + bank = bank_; + } + + function name() public view returns (string memory) { + return bank.name(denom); + } + + function symbol() public view returns (string memory) { + return bank.symbol(denom); + } + + function decimals() public view returns (uint8) { + return bank.decimals(denom); + } + + function totalSupply() public view returns (uint256) { + return bank.totalSupply(denom); + } + + function balanceOf(address account) public view returns (uint256) { + return bank.balanceOf(account, denom); + } + + function transfer(address to, uint256 value) public returns (bool) { + _transfer(msg.sender, to, value); + return true; + } + + function approve(address spender, uint256 value) public returns (bool) { + _approve(msg.sender, spender, value); + return true; + } + + function transferFrom(address from, address to, uint256 value) public returns (bool) { + address spender = msg.sender; + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + function _transfer(address from, address to, uint256 value) internal { + if (from == address(0)) { + revert ERC20InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + + bank.transferFrom(from, to, value, denom); + emit Transfer(from, to, value); + } + + function _approve(address owner, address spender, uint256 value) internal { + _approve(owner, spender, value, true); + } + + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + allowance[owner][spender] = value; + if (emitEvent) { + emit Approval(owner, spender, value); + } + } + + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { + uint256 currentAllowance = allowance[owner][spender]; + if (currentAllowance < type(uint256).max) { + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); + } + unchecked { + _approve(owner, spender, currentAllowance - value, false); + } + } + } +} diff --git a/precompiles/bank/bank.abi.go b/precompiles/bank/bank.abi.go new file mode 100644 index 000000000..7bcf81b09 --- /dev/null +++ b/precompiles/bank/bank.abi.go @@ -0,0 +1,1815 @@ +// Code generated by go-abi. DO NOT EDIT. + +package bank + +import ( + "encoding/binary" + "io" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/yihuang/go-abi" +) + +// Function selectors +var ( + // balanceOf(address,string) + BalanceOfSelector = [4]byte{0xb9, 0xb0, 0x92, 0xc8} + // balances(address) + BalancesSelector = [4]byte{0x27, 0xe2, 0x35, 0xe3} + // decimals(string) + DecimalsSelector = [4]byte{0x3b, 0x2b, 0x32, 0x04} + // erc20ctor(string,address) + Erc20ctorSelector = [4]byte{0x11, 0x31, 0x32, 0x62} + // name(string) + NameSelector = [4]byte{0x5b, 0x43, 0xbc, 0x99} + // supplyOf(address) + SupplyOfSelector = [4]byte{0x62, 0x40, 0x0e, 0x4c} + // symbol(string) + SymbolSelector = [4]byte{0x41, 0xbb, 0x05, 0x59} + // totalSupply() + TotalSupplySelector = [4]byte{0x18, 0x16, 0x0d, 0xdd} + // totalSupply(string) + TotalSupply0Selector = [4]byte{0xc4, 0x15, 0xdb, 0x13} + // transferFrom(address,address,uint256,string) + TransferFromSelector = [4]byte{0x1a, 0xf7, 0x16, 0xba} +) + +// Big endian integer versions of function selectors +const ( + BalanceOfID = 3115356872 + BalancesID = 669136355 + DecimalsID = 992686596 + Erc20ctorID = 288436834 + NameID = 1531165849 + SupplyOfID = 1648365132 + SymbolID = 1102775641 + TotalSupplyID = 404098525 + TotalSupply0ID = 3289766675 + TransferFromID = 452400826 +) + +const BalanceStaticSize = 64 + +var _ abi.Tuple = (*Balance)(nil) + +// Balance represents an ABI tuple +type Balance struct { + ContractAddress common.Address + Amount *big.Int +} + +// EncodedSize returns the total encoded size of Balance +func (t Balance) EncodedSize() int { + dynamicSize := 0 + + return BalanceStaticSize + dynamicSize +} + +// EncodeTo encodes Balance to ABI bytes in the provided buffer +func (value Balance) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalanceStaticSize // Start dynamic data after static section + // Field ContractAddress: address + if _, err := abi.EncodeAddress(value.ContractAddress, buf[0:]); err != nil { + return 0, err + } + + // Field Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes Balance to ABI bytes +func (value Balance) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes Balance from ABI bytes in the provided buffer +func (t *Balance) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 64 + // Decode static field ContractAddress: address + t.ContractAddress, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// EncodeBalanceSlice encodes (address,uint256)[] to ABI bytes +func EncodeBalanceSlice(value []Balance, buf []byte) (int, error) { + // Encode length + binary.BigEndian.PutUint64(buf[24:32], uint64(len(value))) + buf = buf[32:] + + // Encode elements with static types + var offset int + for _, elem := range value { + n, err := elem.EncodeTo(buf[offset:]) + if err != nil { + return 0, err + } + offset += n + } + + return offset + 32, nil +} + +// SizeBalanceSlice returns the encoded size of (address,uint256)[] +func SizeBalanceSlice(value []Balance) int { + size := 32 + 64*len(value) // length + static elements + return size +} + +// DecodeBalanceSlice decodes (address,uint256)[] from ABI bytes +func DecodeBalanceSlice(data []byte) ([]Balance, int, error) { + // Decode length + if len(data) < 32 { + return nil, 0, io.ErrUnexpectedEOF + } + length, err := abi.DecodeSize(data) + if err != nil { + return nil, 0, err + } + data = data[32:] + if length > len(data) || length*64 > len(data) { + return nil, 0, io.ErrUnexpectedEOF + } + var ( + n int + offset int + ) + // Decode elements with static types + result := make([]Balance, length) + for i := 0; i < length; i++ { + n, err = result[i].Decode(data[offset:]) + if err != nil { + return nil, 0, err + } + offset += n + } + return result, offset + 32, nil +} + +var _ abi.Method = (*BalanceOfCall)(nil) + +const BalanceOfCallStaticSize = 64 + +var _ abi.Tuple = (*BalanceOfCall)(nil) + +// BalanceOfCall represents an ABI tuple +type BalanceOfCall struct { + Account common.Address + Denom string +} + +// EncodedSize returns the total encoded size of BalanceOfCall +func (t BalanceOfCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return BalanceOfCallStaticSize + dynamicSize +} + +// EncodeTo encodes BalanceOfCall to ABI bytes in the provided buffer +func (value BalanceOfCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalanceOfCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Account: address + if _, err := abi.EncodeAddress(value.Account, buf[0:]); err != nil { + return 0, err + } + + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[32+24:32+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes BalanceOfCall to ABI bytes +func (value BalanceOfCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes BalanceOfCall from ABI bytes in the provided buffer +func (t *BalanceOfCall) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 64 + // Decode static field Account: address + t.Account, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[32:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t BalanceOfCall) GetMethodName() string { + return "balanceOf" +} + +// GetMethodID returns the function id +func (t BalanceOfCall) GetMethodID() uint32 { + return BalanceOfID +} + +// GetMethodSelector returns the function selector +func (t BalanceOfCall) GetMethodSelector() [4]byte { + return BalanceOfSelector +} + +// EncodeWithSelector encodes balanceOf arguments to ABI bytes including function selector +func (t BalanceOfCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], BalanceOfSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewBalanceOfCall constructs a new BalanceOfCall +func NewBalanceOfCall( + account common.Address, + denom string, +) *BalanceOfCall { + return &BalanceOfCall{ + Account: account, + Denom: denom, + } +} + +const BalanceOfReturnStaticSize = 32 + +var _ abi.Tuple = (*BalanceOfReturn)(nil) + +// BalanceOfReturn represents an ABI tuple +type BalanceOfReturn struct { + Balance *big.Int +} + +// EncodedSize returns the total encoded size of BalanceOfReturn +func (t BalanceOfReturn) EncodedSize() int { + dynamicSize := 0 + + return BalanceOfReturnStaticSize + dynamicSize +} + +// EncodeTo encodes BalanceOfReturn to ABI bytes in the provided buffer +func (value BalanceOfReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalanceOfReturnStaticSize // Start dynamic data after static section + // Field Balance: uint256 + if _, err := abi.EncodeUint256(value.Balance, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes BalanceOfReturn to ABI bytes +func (value BalanceOfReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes BalanceOfReturn from ABI bytes in the provided buffer +func (t *BalanceOfReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Balance: uint256 + t.Balance, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*BalancesCall)(nil) + +const BalancesCallStaticSize = 32 + +var _ abi.Tuple = (*BalancesCall)(nil) + +// BalancesCall represents an ABI tuple +type BalancesCall struct { + Account common.Address +} + +// EncodedSize returns the total encoded size of BalancesCall +func (t BalancesCall) EncodedSize() int { + dynamicSize := 0 + + return BalancesCallStaticSize + dynamicSize +} + +// EncodeTo encodes BalancesCall to ABI bytes in the provided buffer +func (value BalancesCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalancesCallStaticSize // Start dynamic data after static section + // Field Account: address + if _, err := abi.EncodeAddress(value.Account, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes BalancesCall to ABI bytes +func (value BalancesCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes BalancesCall from ABI bytes in the provided buffer +func (t *BalancesCall) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Account: address + t.Account, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t BalancesCall) GetMethodName() string { + return "balances" +} + +// GetMethodID returns the function id +func (t BalancesCall) GetMethodID() uint32 { + return BalancesID +} + +// GetMethodSelector returns the function selector +func (t BalancesCall) GetMethodSelector() [4]byte { + return BalancesSelector +} + +// EncodeWithSelector encodes balances arguments to ABI bytes including function selector +func (t BalancesCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], BalancesSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewBalancesCall constructs a new BalancesCall +func NewBalancesCall( + account common.Address, +) *BalancesCall { + return &BalancesCall{ + Account: account, + } +} + +const BalancesReturnStaticSize = 32 + +var _ abi.Tuple = (*BalancesReturn)(nil) + +// BalancesReturn represents an ABI tuple +type BalancesReturn struct { + Balances []Balance +} + +// EncodedSize returns the total encoded size of BalancesReturn +func (t BalancesReturn) EncodedSize() int { + dynamicSize := 0 + dynamicSize += SizeBalanceSlice(t.Balances) + + return BalancesReturnStaticSize + dynamicSize +} + +// EncodeTo encodes BalancesReturn to ABI bytes in the provided buffer +func (value BalancesReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalancesReturnStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Balances: (address,uint256)[] + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = EncodeBalanceSlice(value.Balances, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes BalancesReturn to ABI bytes +func (value BalancesReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes BalancesReturn from ABI bytes in the provided buffer +func (t *BalancesReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Balances + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Balances, n, err = DecodeBalanceSlice(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +var _ abi.Method = (*DecimalsCall)(nil) + +const DecimalsCallStaticSize = 32 + +var _ abi.Tuple = (*DecimalsCall)(nil) + +// DecimalsCall represents an ABI tuple +type DecimalsCall struct { + Denom string +} + +// EncodedSize returns the total encoded size of DecimalsCall +func (t DecimalsCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return DecimalsCallStaticSize + dynamicSize +} + +// EncodeTo encodes DecimalsCall to ABI bytes in the provided buffer +func (value DecimalsCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := DecimalsCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes DecimalsCall to ABI bytes +func (value DecimalsCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes DecimalsCall from ABI bytes in the provided buffer +func (t *DecimalsCall) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t DecimalsCall) GetMethodName() string { + return "decimals" +} + +// GetMethodID returns the function id +func (t DecimalsCall) GetMethodID() uint32 { + return DecimalsID +} + +// GetMethodSelector returns the function selector +func (t DecimalsCall) GetMethodSelector() [4]byte { + return DecimalsSelector +} + +// EncodeWithSelector encodes decimals arguments to ABI bytes including function selector +func (t DecimalsCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], DecimalsSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewDecimalsCall constructs a new DecimalsCall +func NewDecimalsCall( + denom string, +) *DecimalsCall { + return &DecimalsCall{ + Denom: denom, + } +} + +const DecimalsReturnStaticSize = 32 + +var _ abi.Tuple = (*DecimalsReturn)(nil) + +// DecimalsReturn represents an ABI tuple +type DecimalsReturn struct { + Decimals uint8 +} + +// EncodedSize returns the total encoded size of DecimalsReturn +func (t DecimalsReturn) EncodedSize() int { + dynamicSize := 0 + + return DecimalsReturnStaticSize + dynamicSize +} + +// EncodeTo encodes DecimalsReturn to ABI bytes in the provided buffer +func (value DecimalsReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := DecimalsReturnStaticSize // Start dynamic data after static section + // Field Decimals: uint8 + if _, err := abi.EncodeUint8(value.Decimals, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes DecimalsReturn to ABI bytes +func (value DecimalsReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes DecimalsReturn from ABI bytes in the provided buffer +func (t *DecimalsReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Decimals: uint8 + t.Decimals, _, err = abi.DecodeUint8(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*Erc20ctorCall)(nil) + +const Erc20ctorCallStaticSize = 64 + +var _ abi.Tuple = (*Erc20ctorCall)(nil) + +// Erc20ctorCall represents an ABI tuple +type Erc20ctorCall struct { + Denom string + Bank common.Address +} + +// EncodedSize returns the total encoded size of Erc20ctorCall +func (t Erc20ctorCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return Erc20ctorCallStaticSize + dynamicSize +} + +// EncodeTo encodes Erc20ctorCall to ABI bytes in the provided buffer +func (value Erc20ctorCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := Erc20ctorCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field Bank: address + if _, err := abi.EncodeAddress(value.Bank, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes Erc20ctorCall to ABI bytes +func (value Erc20ctorCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes Erc20ctorCall from ABI bytes in the provided buffer +func (t *Erc20ctorCall) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 64 + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode static field Bank: address + t.Bank, _, err = abi.DecodeAddress(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t Erc20ctorCall) GetMethodName() string { + return "erc20ctor" +} + +// GetMethodID returns the function id +func (t Erc20ctorCall) GetMethodID() uint32 { + return Erc20ctorID +} + +// GetMethodSelector returns the function selector +func (t Erc20ctorCall) GetMethodSelector() [4]byte { + return Erc20ctorSelector +} + +// EncodeWithSelector encodes erc20ctor arguments to ABI bytes including function selector +func (t Erc20ctorCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], Erc20ctorSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewErc20ctorCall constructs a new Erc20ctorCall +func NewErc20ctorCall( + denom string, + bank common.Address, +) *Erc20ctorCall { + return &Erc20ctorCall{ + Denom: denom, + Bank: bank, + } +} + +// Erc20ctorReturn represents the output arguments for erc20ctor function +type Erc20ctorReturn struct { + abi.EmptyTuple +} + +var _ abi.Method = (*NameCall)(nil) + +const NameCallStaticSize = 32 + +var _ abi.Tuple = (*NameCall)(nil) + +// NameCall represents an ABI tuple +type NameCall struct { + Denom string +} + +// EncodedSize returns the total encoded size of NameCall +func (t NameCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return NameCallStaticSize + dynamicSize +} + +// EncodeTo encodes NameCall to ABI bytes in the provided buffer +func (value NameCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := NameCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes NameCall to ABI bytes +func (value NameCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes NameCall from ABI bytes in the provided buffer +func (t *NameCall) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t NameCall) GetMethodName() string { + return "name" +} + +// GetMethodID returns the function id +func (t NameCall) GetMethodID() uint32 { + return NameID +} + +// GetMethodSelector returns the function selector +func (t NameCall) GetMethodSelector() [4]byte { + return NameSelector +} + +// EncodeWithSelector encodes name arguments to ABI bytes including function selector +func (t NameCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], NameSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewNameCall constructs a new NameCall +func NewNameCall( + denom string, +) *NameCall { + return &NameCall{ + Denom: denom, + } +} + +const NameReturnStaticSize = 32 + +var _ abi.Tuple = (*NameReturn)(nil) + +// NameReturn represents an ABI tuple +type NameReturn struct { + Name string +} + +// EncodedSize returns the total encoded size of NameReturn +func (t NameReturn) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Name) + + return NameReturnStaticSize + dynamicSize +} + +// EncodeTo encodes NameReturn to ABI bytes in the provided buffer +func (value NameReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := NameReturnStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Name: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Name, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes NameReturn to ABI bytes +func (value NameReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes NameReturn from ABI bytes in the provided buffer +func (t *NameReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Name + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Name, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +var _ abi.Method = (*SupplyOfCall)(nil) + +const SupplyOfCallStaticSize = 32 + +var _ abi.Tuple = (*SupplyOfCall)(nil) + +// SupplyOfCall represents an ABI tuple +type SupplyOfCall struct { + Contract common.Address +} + +// EncodedSize returns the total encoded size of SupplyOfCall +func (t SupplyOfCall) EncodedSize() int { + dynamicSize := 0 + + return SupplyOfCallStaticSize + dynamicSize +} + +// EncodeTo encodes SupplyOfCall to ABI bytes in the provided buffer +func (value SupplyOfCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := SupplyOfCallStaticSize // Start dynamic data after static section + // Field Contract: address + if _, err := abi.EncodeAddress(value.Contract, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes SupplyOfCall to ABI bytes +func (value SupplyOfCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes SupplyOfCall from ABI bytes in the provided buffer +func (t *SupplyOfCall) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Contract: address + t.Contract, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t SupplyOfCall) GetMethodName() string { + return "supplyOf" +} + +// GetMethodID returns the function id +func (t SupplyOfCall) GetMethodID() uint32 { + return SupplyOfID +} + +// GetMethodSelector returns the function selector +func (t SupplyOfCall) GetMethodSelector() [4]byte { + return SupplyOfSelector +} + +// EncodeWithSelector encodes supplyOf arguments to ABI bytes including function selector +func (t SupplyOfCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], SupplyOfSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewSupplyOfCall constructs a new SupplyOfCall +func NewSupplyOfCall( + contract common.Address, +) *SupplyOfCall { + return &SupplyOfCall{ + Contract: contract, + } +} + +const SupplyOfReturnStaticSize = 32 + +var _ abi.Tuple = (*SupplyOfReturn)(nil) + +// SupplyOfReturn represents an ABI tuple +type SupplyOfReturn struct { + TotalSupply *big.Int +} + +// EncodedSize returns the total encoded size of SupplyOfReturn +func (t SupplyOfReturn) EncodedSize() int { + dynamicSize := 0 + + return SupplyOfReturnStaticSize + dynamicSize +} + +// EncodeTo encodes SupplyOfReturn to ABI bytes in the provided buffer +func (value SupplyOfReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := SupplyOfReturnStaticSize // Start dynamic data after static section + // Field TotalSupply: uint256 + if _, err := abi.EncodeUint256(value.TotalSupply, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes SupplyOfReturn to ABI bytes +func (value SupplyOfReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes SupplyOfReturn from ABI bytes in the provided buffer +func (t *SupplyOfReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field TotalSupply: uint256 + t.TotalSupply, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*SymbolCall)(nil) + +const SymbolCallStaticSize = 32 + +var _ abi.Tuple = (*SymbolCall)(nil) + +// SymbolCall represents an ABI tuple +type SymbolCall struct { + Denom string +} + +// EncodedSize returns the total encoded size of SymbolCall +func (t SymbolCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return SymbolCallStaticSize + dynamicSize +} + +// EncodeTo encodes SymbolCall to ABI bytes in the provided buffer +func (value SymbolCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := SymbolCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes SymbolCall to ABI bytes +func (value SymbolCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes SymbolCall from ABI bytes in the provided buffer +func (t *SymbolCall) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t SymbolCall) GetMethodName() string { + return "symbol" +} + +// GetMethodID returns the function id +func (t SymbolCall) GetMethodID() uint32 { + return SymbolID +} + +// GetMethodSelector returns the function selector +func (t SymbolCall) GetMethodSelector() [4]byte { + return SymbolSelector +} + +// EncodeWithSelector encodes symbol arguments to ABI bytes including function selector +func (t SymbolCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], SymbolSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewSymbolCall constructs a new SymbolCall +func NewSymbolCall( + denom string, +) *SymbolCall { + return &SymbolCall{ + Denom: denom, + } +} + +const SymbolReturnStaticSize = 32 + +var _ abi.Tuple = (*SymbolReturn)(nil) + +// SymbolReturn represents an ABI tuple +type SymbolReturn struct { + Symbol string +} + +// EncodedSize returns the total encoded size of SymbolReturn +func (t SymbolReturn) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Symbol) + + return SymbolReturnStaticSize + dynamicSize +} + +// EncodeTo encodes SymbolReturn to ABI bytes in the provided buffer +func (value SymbolReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := SymbolReturnStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Symbol: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Symbol, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes SymbolReturn to ABI bytes +func (value SymbolReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes SymbolReturn from ABI bytes in the provided buffer +func (t *SymbolReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Symbol + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Symbol, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +var _ abi.Method = (*TotalSupplyCall)(nil) + +// TotalSupplyCall represents the input arguments for totalSupply function +type TotalSupplyCall struct { + abi.EmptyTuple +} + +// GetMethodName returns the function name +func (t TotalSupplyCall) GetMethodName() string { + return "totalSupply" +} + +// GetMethodID returns the function id +func (t TotalSupplyCall) GetMethodID() uint32 { + return TotalSupplyID +} + +// GetMethodSelector returns the function selector +func (t TotalSupplyCall) GetMethodSelector() [4]byte { + return TotalSupplySelector +} + +// EncodeWithSelector encodes totalSupply arguments to ABI bytes including function selector +func (t TotalSupplyCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], TotalSupplySelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewTotalSupplyCall constructs a new TotalSupplyCall +func NewTotalSupplyCall() *TotalSupplyCall { + return &TotalSupplyCall{} +} + +const TotalSupplyReturnStaticSize = 32 + +var _ abi.Tuple = (*TotalSupplyReturn)(nil) + +// TotalSupplyReturn represents an ABI tuple +type TotalSupplyReturn struct { + TotalSupply []Balance +} + +// EncodedSize returns the total encoded size of TotalSupplyReturn +func (t TotalSupplyReturn) EncodedSize() int { + dynamicSize := 0 + dynamicSize += SizeBalanceSlice(t.TotalSupply) + + return TotalSupplyReturnStaticSize + dynamicSize +} + +// EncodeTo encodes TotalSupplyReturn to ABI bytes in the provided buffer +func (value TotalSupplyReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TotalSupplyReturnStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field TotalSupply: (address,uint256)[] + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = EncodeBalanceSlice(value.TotalSupply, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes TotalSupplyReturn to ABI bytes +func (value TotalSupplyReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TotalSupplyReturn from ABI bytes in the provided buffer +func (t *TotalSupplyReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field TotalSupply + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.TotalSupply, n, err = DecodeBalanceSlice(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +var _ abi.Method = (*TotalSupply0Call)(nil) + +const TotalSupply0CallStaticSize = 32 + +var _ abi.Tuple = (*TotalSupply0Call)(nil) + +// TotalSupply0Call represents an ABI tuple +type TotalSupply0Call struct { + Denom string +} + +// EncodedSize returns the total encoded size of TotalSupply0Call +func (t TotalSupply0Call) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return TotalSupply0CallStaticSize + dynamicSize +} + +// EncodeTo encodes TotalSupply0Call to ABI bytes in the provided buffer +func (value TotalSupply0Call) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TotalSupply0CallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes TotalSupply0Call to ABI bytes +func (value TotalSupply0Call) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TotalSupply0Call from ABI bytes in the provided buffer +func (t *TotalSupply0Call) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t TotalSupply0Call) GetMethodName() string { + return "totalSupply0" +} + +// GetMethodID returns the function id +func (t TotalSupply0Call) GetMethodID() uint32 { + return TotalSupply0ID +} + +// GetMethodSelector returns the function selector +func (t TotalSupply0Call) GetMethodSelector() [4]byte { + return TotalSupply0Selector +} + +// EncodeWithSelector encodes totalSupply0 arguments to ABI bytes including function selector +func (t TotalSupply0Call) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], TotalSupply0Selector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewTotalSupply0Call constructs a new TotalSupply0Call +func NewTotalSupply0Call( + denom string, +) *TotalSupply0Call { + return &TotalSupply0Call{ + Denom: denom, + } +} + +const TotalSupply0ReturnStaticSize = 32 + +var _ abi.Tuple = (*TotalSupply0Return)(nil) + +// TotalSupply0Return represents an ABI tuple +type TotalSupply0Return struct { + Supply *big.Int +} + +// EncodedSize returns the total encoded size of TotalSupply0Return +func (t TotalSupply0Return) EncodedSize() int { + dynamicSize := 0 + + return TotalSupply0ReturnStaticSize + dynamicSize +} + +// EncodeTo encodes TotalSupply0Return to ABI bytes in the provided buffer +func (value TotalSupply0Return) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TotalSupply0ReturnStaticSize // Start dynamic data after static section + // Field Supply: uint256 + if _, err := abi.EncodeUint256(value.Supply, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TotalSupply0Return to ABI bytes +func (value TotalSupply0Return) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TotalSupply0Return from ABI bytes in the provided buffer +func (t *TotalSupply0Return) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Supply: uint256 + t.Supply, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*TransferFromCall)(nil) + +const TransferFromCallStaticSize = 128 + +var _ abi.Tuple = (*TransferFromCall)(nil) + +// TransferFromCall represents an ABI tuple +type TransferFromCall struct { + From common.Address + To common.Address + Value *big.Int + Denom string +} + +// EncodedSize returns the total encoded size of TransferFromCall +func (t TransferFromCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return TransferFromCallStaticSize + dynamicSize +} + +// EncodeTo encodes TransferFromCall to ABI bytes in the provided buffer +func (value TransferFromCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferFromCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field From: address + if _, err := abi.EncodeAddress(value.From, buf[0:]); err != nil { + return 0, err + } + + // Field To: address + if _, err := abi.EncodeAddress(value.To, buf[32:]); err != nil { + return 0, err + } + + // Field Value: uint256 + if _, err := abi.EncodeUint256(value.Value, buf[64:]); err != nil { + return 0, err + } + + // Field Denom: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[96+24:96+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Denom, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes TransferFromCall to ABI bytes +func (value TransferFromCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferFromCall from ABI bytes in the provided buffer +func (t *TransferFromCall) Decode(data []byte) (int, error) { + if len(data) < 128 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 128 + // Decode static field From: address + t.From, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + // Decode static field To: address + t.To, _, err = abi.DecodeAddress(data[32:]) + if err != nil { + return 0, err + } + // Decode static field Value: uint256 + t.Value, _, err = abi.DecodeUint256(data[64:]) + if err != nil { + return 0, err + } + // Decode dynamic field Denom + { + offset, err = abi.DecodeSize(data[96:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t TransferFromCall) GetMethodName() string { + return "transferFrom" +} + +// GetMethodID returns the function id +func (t TransferFromCall) GetMethodID() uint32 { + return TransferFromID +} + +// GetMethodSelector returns the function selector +func (t TransferFromCall) GetMethodSelector() [4]byte { + return TransferFromSelector +} + +// EncodeWithSelector encodes transferFrom arguments to ABI bytes including function selector +func (t TransferFromCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], TransferFromSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewTransferFromCall constructs a new TransferFromCall +func NewTransferFromCall( + from common.Address, + to common.Address, + value *big.Int, + denom string, +) *TransferFromCall { + return &TransferFromCall{ + From: from, + To: to, + Value: value, + Denom: denom, + } +} + +const TransferFromReturnStaticSize = 32 + +var _ abi.Tuple = (*TransferFromReturn)(nil) + +// TransferFromReturn represents an ABI tuple +type TransferFromReturn struct { + Field1 bool +} + +// EncodedSize returns the total encoded size of TransferFromReturn +func (t TransferFromReturn) EncodedSize() int { + dynamicSize := 0 + + return TransferFromReturnStaticSize + dynamicSize +} + +// EncodeTo encodes TransferFromReturn to ABI bytes in the provided buffer +func (value TransferFromReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferFromReturnStaticSize // Start dynamic data after static section + // Field Field1: bool + if _, err := abi.EncodeBool(value.Field1, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TransferFromReturn to ABI bytes +func (value TransferFromReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferFromReturn from ABI bytes in the provided buffer +func (t *TransferFromReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Field1: bool + t.Field1, _, err = abi.DecodeBool(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 5da9aef5a..650e86d9e 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -23,18 +23,26 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -const ( - // GasBalances defines the gas cost for a single ERC-20 balanceOf query - GasBalances = 2_851 - - // GasTotalSupply defines the gas cost for a single ERC-20 totalSupply query - GasTotalSupply = 2_477 - - // GasSupplyOf defines the gas cost for a single ERC-20 supplyOf query, taken from totalSupply of ERC20 - GasSupplyOf = 2_477 -) - -var _ vm.PrecompiledContract = &Precompile{} +//go:generate go run ../cmd -var=HumanABI -output bank.abi.go + +var HumanABI = []string{ + // backwards compatibility + "struct Balance{ address contractAddress; uint amount; }", + "function balances(address account) returns (Balance[] balances)", + "function totalSupply() returns (Balance[] totalSupply)", + "function supplyOf(address contract) returns (uint totalSupply)", + + // v2 design + "function name(string denom) returns (string name)", + "function symbol(string denom) returns (string symbol)", + "function decimals(string denom) returns (uint8 decimals)", + "function totalSupply(string denom) returns (uint256 supply)", + "function balanceOf(address account, string denom) returns (uint256 balance)", + "function transferFrom(address from, address to, uint256 value, string denom) returns (bool)", + + // generate the erc20 constructor abi + "function erc20ctor(string denom, address bank)", +} var ( // Embed abi json file to the executable binary. Needed when importing as dependency. @@ -52,19 +60,36 @@ func init() { } } +const ( + // GasBalances defines the gas cost for a single ERC-20 balanceOf query + GasBalances = 2_851 + + // GasTotalSupply defines the gas cost for a single ERC-20 totalSupply query + GasTotalSupply = 2_477 + + // GasSupplyOf defines the gas cost for a single ERC-20 supplyOf query, taken from totalSupply of ERC20 + GasSupplyOf = 2_477 + + TransferFromMethod = "transferFrom" +) + +var _ vm.PrecompiledContract = &Precompile{} + // Precompile defines the bank precompile type Precompile struct { cmn.Precompile abi.ABI - bankKeeper cmn.BankKeeper - erc20Keeper cmn.ERC20Keeper + bankMsgServer MsgServer + bankKeeper Keeper + erc20Keeper cmn.ERC20Keeper } // NewPrecompile creates a new bank Precompile instance implementing the // PrecompiledContract interface. func NewPrecompile( - bankKeeper cmn.BankKeeper, + bankMsgServer MsgServer, + bankKeeper Keeper, erc20Keeper cmn.ERC20Keeper, ) *Precompile { // NOTE: we set an empty gas configuration to avoid extra gas costs @@ -75,70 +100,82 @@ func NewPrecompile( TransientKVGasConfig: storetypes.GasConfig{}, ContractAddress: common.HexToAddress(evmtypes.BankPrecompileAddress), }, - ABI: ABI, - bankKeeper: bankKeeper, - erc20Keeper: erc20Keeper, + ABI: ABI, + bankMsgServer: bankMsgServer, + bankKeeper: bankKeeper, + erc20Keeper: erc20Keeper, } } // RequiredGas calculates the precompiled contract's base gas rate. func (p Precompile) RequiredGas(input []byte) uint64 { - // NOTE: This check avoid panicking when trying to decode the method ID - if len(input) < 4 { - return 0 - } - - methodID := input[:4] - - method, err := p.MethodById(methodID) + methodID, input, err := cmn.SplitMethodID(input) if err != nil { - // This should never happen since this method is going to fail during Run return 0 } - switch method.Name { - case BalancesMethod: + // backward compatibility + switch methodID { + case BalancesID: return GasBalances - case TotalSupplyMethod: + case TotalSupplyID: return GasTotalSupply - case SupplyOfMethod: + case SupplyOfID: return GasSupplyOf } - return 0 + return p.Precompile.RequiredGas(input, p.IsTransactionID(methodID)) } func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { - return p.Execute(ctx, contract, readonly) + return p.Execute(ctx, evm.StateDB, contract, readonly) }) } // Execute executes the precompiled contract bank query methods defined in the ABI. -func (p Precompile) Execute(ctx sdk.Context, contract *vm.Contract, readOnly bool) ([]byte, error) { - method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + methodID, input, err := cmn.ParseMethod(contract.Input, readOnly, p.IsTransactionID) if err != nil { return nil, err } - var bz []byte - switch method.Name { - // Bank queries - case BalancesMethod: - bz, err = p.Balances(ctx, method, args) - case TotalSupplyMethod: - bz, err = p.TotalSupply(ctx, method, args) - case SupplyOfMethod: - bz, err = p.SupplyOf(ctx, method, args) + switch methodID { + // backward compatibility + case BalancesID: + return cmn.Run(ctx, p.Balances, input) + case TotalSupplyID: + return cmn.Run(ctx, p.TotalSupply, input) + case SupplyOfID: + return cmn.Run(ctx, p.SupplyOf, input) + + // v2 design + case NameID: + return cmn.Run(ctx, p.Name, input) + case SymbolID: + return cmn.Run(ctx, p.Symbol, input) + case DecimalsID: + return cmn.Run(ctx, p.Decimals, input) + case TotalSupply0ID: + return cmn.Run(ctx, p.TotalSupplyV2, input) + case BalanceOfID: + return cmn.Run(ctx, p.BalanceOf, input) + case TransferFromID: + return cmn.RunWithStateDB(ctx, p.TransferFrom, input, stateDB, contract) + default: - return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + return nil, fmt.Errorf(cmn.ErrUnknownMethodID, methodID) } +} - return bz, err +// IsTransaction checks if the given method name corresponds to a transaction or query. +// It returns false since all bank methods are queries. +func (Precompile) IsTransaction(method *abi.Method) bool { + return method.Name == TransferFromMethod } // IsTransaction checks if the given method name corresponds to a transaction or query. // It returns false since all bank methods are queries. -func (Precompile) IsTransaction(_ *abi.Method) bool { - return false +func (Precompile) IsTransactionID(methodID uint32) bool { + return methodID == TransferFromID } diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go new file mode 100644 index 000000000..766e90767 --- /dev/null +++ b/precompiles/bank/bank_test.go @@ -0,0 +1,348 @@ +package bank + +import ( + "math/big" + "slices" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/holiman/uint256" + "github.com/stretchr/testify/require" + "github.com/yihuang/go-abi" + + _ "embed" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/evm/precompiles/bank/erc20" + "github.com/cosmos/evm/testutil/constants" + evmtypes "github.com/cosmos/evm/x/vm/types" + + "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" + "cosmossdk.io/store" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +//go:generate go run github.com/yihuang/go-abi/cmd -var ERC20ABI -package erc20 -output erc20/erc20.abi.go + +var ERC20ABI = []string{ + "function name() view returns (string name)", + "function symbol() view returns (string symbol)", + "function decimals() view returns (uint8 decimals)", + "function totalSupply() view returns (uint256 supply)", + "function balanceOf(address account) view returns (uint256 balance)", + "function transfer(address to, uint256 amount) returns (bool success)", + "function transferFrom(address from, address to, uint256 amount) returns (bool success)", + "event Transfer(address indexed from, address indexed to, uint256 amount)", + "event Approval(address indexed owner, address indexed spender, uint256 amount)", +} + +var ( + BankPrecompile = common.HexToAddress(evmtypes.BankPrecompileAddress) + GasLimit = uint64(100000000) +) + +type TokenInfo struct { + Denom string + DisplayDenom string + Name string + Symbol string + Decimals byte +} + +func Setup(t *testing.T, token TokenInfo, mintTo common.Address, mintAmount uint64) *vm.EVM { + t.Helper() + + chainID := uint64(constants.EighteenDecimalsChainID) + configurator := evmtypes.NewEVMConfigurator() + configurator.ResetTestConfig() + // set global chain config + ethCfg := evmtypes.DefaultChainConfig(chainID) + if err := evmtypes.SetChainConfig(ethCfg); err != nil { + panic(err) + } + err := configurator. + WithExtendedEips(evmtypes.DefaultCosmosEVMActivators). + // NOTE: we're using the 18 decimals default for the example chain + WithEVMCoinInfo(constants.ChainsCoinInfo[chainID]). + Configure() + + require.NoError(t, err) + nativeDenom := evmtypes.GetEVMCoinDenom() + + rawdb := dbm.NewMemDB() + logger := log.NewNopLogger() + ms := store.NewCommitMultiStore(rawdb, logger, nil) + ctx := sdk.NewContext(ms, cmtproto.Header{}, false, logger) + evm := NewMockEVM(ctx) + + bankKeeper := NewMockBankKeeper() + msgServer := NewBankMsgServer(bankKeeper) + precompile := NewPrecompile(msgServer, bankKeeper, nil) + evm.WithPrecompiles(map[common.Address]vm.PrecompiledContract{ + precompile.Address(): precompile, + }) + + // init token + bankKeeper.registerDenom(token.Denom, banktypes.Metadata{ + Symbol: token.Symbol, Name: token.Name, Display: token.DisplayDenom, DenomUnits: []*banktypes.DenomUnit{ + { + Denom: token.Denom, + Exponent: 0, + }, + { + Denom: token.DisplayDenom, + Exponent: uint32(token.Decimals), + }, + }, + }) + bankKeeper.registerDenom(nativeDenom, banktypes.Metadata{ + Symbol: "NATIVE", Name: "Native Token", Display: evmtypes.GetEVMCoinDisplayDenom(), DenomUnits: []*banktypes.DenomUnit{ + { + Denom: nativeDenom, + Exponent: 0, + }, + { + Denom: evmtypes.GetEVMCoinDisplayDenom(), + Exponent: 18, + }, + }, + }) + bankKeeper.mint(mintTo.Bytes(), sdk.NewCoins(sdk.NewCoin(token.Denom, sdkmath.NewIntFromUint64(mintAmount)))) + bankKeeper.mint(mintTo.Bytes(), sdk.NewCoins(sdk.NewCoin(nativeDenom, sdkmath.NewIntFromUint64(mintAmount)))) + + DeployCreate2(t, evm) + DeployERC20(t, evm, BankPrecompile, token.Denom) + + return evm +} + +func TestERC20ContractAddress(t *testing.T) { + denom := "uatom" + contract := common.HexToAddress(evmtypes.BankPrecompileAddress) + expected := common.HexToAddress("0x46514a468D158DC165192793EB8Ba44480e513e6") + + result, err := ERC20ContractAddress(contract, denom) + require.NoError(t, err) + require.Equal(t, expected, result) +} + +// TestBankPrecompile tests calling bank precompile directly +func TestBankPrecompile(t *testing.T) { + user1 := common.BigToAddress(big.NewInt(1)) + user2 := common.BigToAddress(big.NewInt(2)) + token := TokenInfo{ + Denom: "denom", + DisplayDenom: "display", + Symbol: "COIN", + Name: "Test Coin", + Decimals: byte(18), + } + amount := uint64(1000) + erc20Address, err := ERC20ContractAddress(BankPrecompile, token.Denom) + require.NoError(t, err) + + setup := func(t *testing.T) *vm.EVM { + t.Helper() + return Setup(t, token, user1, amount) + } + + testCases := []struct { + name string + caller common.Address + args abi.Method + output abi.Encode + expErr error + }{ + {"name", user1, NewNameCall(token.Denom), &NameReturn{token.Name}, nil}, + {"symbol", user1, NewSymbolCall(token.Denom), &SymbolReturn{token.Symbol}, nil}, + {"decimals", user1, NewDecimalsCall(token.Denom), &DecimalsReturn{token.Decimals}, nil}, + { + "supplyOf", user1, NewTotalSupply0Call(token.Denom), + &TotalSupply0Return{new(big.Int).SetUint64(amount)}, + nil, + }, + { + "balanceOf", + user1, + NewBalanceOfCall(user1, token.Denom), + &BalanceOfReturn{new(big.Int).SetUint64(amount)}, + nil, + }, + { + "balanceOf-empty", user2, + NewBalanceOfCall(user2, token.Denom), + &BalanceOfReturn{new(big.Int)}, + nil, + }, + { + "transferFrom-owner", user1, + NewTransferFromCall(user1, user2, big.NewInt(100), token.Denom), + &TransferFromReturn{true}, + nil, + }, + { + "transferFrom-erc20", erc20Address, + NewTransferFromCall(user1, user2, big.NewInt(100), token.Denom), + &TransferFromReturn{true}, + nil, + }, + { + "transferFrom-unauthorized", user2, + NewTransferFromCall(user1, user2, big.NewInt(100), token.Denom), + nil, + vm.ErrExecutionReverted, + }, + { + "transferFrom-insufficient-balance", user2, + NewTransferFromCall(user2, user1, big.NewInt(100), token.Denom), + nil, + vm.ErrExecutionReverted, + }, + {"invalid-method", user1, erc20.NewTransferCall(user1, big.NewInt(100)), nil, vm.ErrExecutionReverted}, + {"name-invalid-denom", user1, NewNameCall("non-exist"), nil, vm.ErrExecutionReverted}, + {"symbol-invalid-denom", user1, NewSymbolCall("non-exist"), nil, vm.ErrExecutionReverted}, + {"decimals-invalid-denom", user1, NewDecimalsCall("non-exist"), nil, vm.ErrExecutionReverted}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + evm := setup(t) + input, err := tc.args.EncodeWithSelector() + require.NoError(t, err) + ret, _, err := evm.Call(tc.caller, BankPrecompile, input, GasLimit, uint256.NewInt(0)) + if tc.expErr != nil { + require.Equal(t, tc.expErr, err) + } else { + require.NoError(t, err) + expOutput, err := tc.output.Encode() + require.NoError(t, err) + require.Equal(t, expOutput, ret) + } + }) + } +} + +// TestBankERC20 tests bank precompile through the ERC20 interface +func TestBankERC20(t *testing.T) { + zero := common.BigToAddress(big.NewInt(0)) + user1 := common.BigToAddress(big.NewInt(1)) + user2 := common.BigToAddress(big.NewInt(2)) + info := TokenInfo{ + Denom: "denom", + DisplayDenom: "display", + Symbol: "COIN", + Name: "Test Coin", + Decimals: byte(18), + } + amount := uint64(1000) + bigAmount := new(big.Int).SetUint64(amount) + token, err := ERC20ContractAddress(BankPrecompile, info.Denom) + require.NoError(t, err) + nativeERC20, err := ERC20ContractAddress(BankPrecompile, evmtypes.GetEVMCoinDenom()) + require.NoError(t, err) + + setup := func(t *testing.T) *vm.EVM { + t.Helper() + evm := Setup(t, info, user1, amount) + DeployERC20(t, evm, BankPrecompile, evmtypes.GetEVMCoinDenom()) + return evm + } + + testCases := []struct { + name string + caller common.Address + token common.Address + input abi.Method + output abi.Encode + expErr error + }{ + {"name", zero, token, erc20.NewNameCall(), &erc20.NameReturn{Name: info.Name}, nil}, + {"symbol", zero, token, erc20.NewSymbolCall(), &erc20.SymbolReturn{Symbol: info.Symbol}, nil}, + {"decimals", zero, token, erc20.NewDecimalsCall(), &erc20.DecimalsReturn{Decimals: info.Decimals}, nil}, + {"totalSupply", zero, token, erc20.NewTotalSupplyCall(), &erc20.TotalSupplyReturn{Supply: bigAmount}, nil}, + { + "balanceOf", zero, token, + erc20.NewBalanceOfCall(user1), + &erc20.BalanceOfReturn{Balance: bigAmount}, + nil, + }, + { + "balanceOf-empty", zero, token, + erc20.NewBalanceOfCall(user2), + &erc20.BalanceOfReturn{Balance: common.Big0}, + nil, + }, + { + "transfer", user1, token, + erc20.NewTransferCall(user1, big.NewInt(100)), + &erc20.TransferReturn{Success: true}, + nil, + }, + { + "transfer-insufficient-balance", user2, token, + erc20.NewTransferCall(user1, big.NewInt(100)), + nil, + vm.ErrExecutionReverted, + }, + { + "native-fail", user1, nativeERC20, + erc20.NewTransferCall(user2, big.NewInt(100)), + nil, + vm.ErrExecutionReverted, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + evm := setup(t) + + input, err := tc.input.EncodeWithSelector() + require.NoError(t, err) + + ret, _, err := evm.Call(tc.caller, tc.token, input, GasLimit, uint256.NewInt(0)) + if tc.expErr != nil { + require.Equal(t, tc.expErr, err) + return + } + + require.NoError(t, err) + expOutput, err := tc.output.Encode() + require.NoError(t, err) + require.Equal(t, expOutput, ret) + }) + } +} + +// DeployCreate2 deploys the deterministic contract factory +// https://github.com/Arachnid/deterministic-deployment-proxy +func DeployCreate2(t *testing.T, evm *vm.EVM) { + t.Helper() + caller := common.HexToAddress("0x3fAB184622Dc19b6109349B94811493BF2a45362") + code := common.FromHex("604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3") + _, address, _, err := evm.Create(caller, code, GasLimit, uint256.NewInt(0)) + require.NoError(t, err) + require.Equal(t, Create2FactoryAddress, address) +} + +func DeployERC20(t *testing.T, evm *vm.EVM, bank common.Address, denom string) { + t.Helper() + caller := common.BigToAddress(common.Big0) + + ctor, err := NewErc20ctorCall(denom, bank).Encode() + require.NoError(t, err) + + input := slices.Concat(ERC20Salt, ERC20Bin, ctor) + _, _, err = evm.Call(caller, Create2FactoryAddress, input, GasLimit, uint256.NewInt(0)) + require.NoError(t, err) + + expAddress, err := ERC20ContractAddress(bank, denom) + require.NoError(t, err) + + require.NotEmpty(t, evm.StateDB.GetCode(expAddress)) +} diff --git a/precompiles/bank/erc20.go b/precompiles/bank/erc20.go new file mode 100644 index 000000000..6ba0636ae --- /dev/null +++ b/precompiles/bank/erc20.go @@ -0,0 +1,41 @@ +package bank + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + _ "embed" +) + +// generated with solc 0.8.30+commit.73712a01: +//go:generate solc --overwrite --optimize --optimize-runs 100000 --via-ir --bin -o . ERC20.sol + +var ( + //go:embed ERC20.bin + ERC20BinHex string + + ERC20Bin = common.Hex2Bytes(ERC20BinHex) + ERC20Salt = common.FromHex("636dd1d57837e7dce61901468217da9975548dcb3ecc24d84567feb93cd11e36") + Create2FactoryAddress = common.HexToAddress("0x4e59b44847b379578588920ca78fbf26c0b4956c") +) + +// ERC20ContractAddress computes the contract address deployed with create2 factory contract. +// create2 factory: https://github.com/Arachnid/deterministic-deployment-proxy +// +// `keccak(0xff || factory || salt || keccak(bytecode || ctor))[12:]` +func ERC20ContractAddress(contract common.Address, denom string) (common.Address, error) { + ctor, err := NewErc20ctorCall(denom, contract).Encode() + if err != nil { + return common.Address{}, err + } + bz := crypto.Keccak256( + []byte{0xff}, + Create2FactoryAddress.Bytes(), + ERC20Salt, + crypto.Keccak256( + ERC20Bin, + ctor, + ), + )[12:] + return common.BytesToAddress(bz), nil +} diff --git a/precompiles/bank/erc20/erc20.abi.go b/precompiles/bank/erc20/erc20.abi.go new file mode 100644 index 000000000..c25b2511c --- /dev/null +++ b/precompiles/bank/erc20/erc20.abi.go @@ -0,0 +1,1204 @@ +// Code generated by go-abi. DO NOT EDIT. + +package erc20 + +import ( + "encoding/binary" + "io" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/yihuang/go-abi" +) + +// Function selectors +var ( + // balanceOf(address) + BalanceOfSelector = [4]byte{0x70, 0xa0, 0x82, 0x31} + // decimals() + DecimalsSelector = [4]byte{0x31, 0x3c, 0xe5, 0x67} + // name() + NameSelector = [4]byte{0x06, 0xfd, 0xde, 0x03} + // symbol() + SymbolSelector = [4]byte{0x95, 0xd8, 0x9b, 0x41} + // totalSupply() + TotalSupplySelector = [4]byte{0x18, 0x16, 0x0d, 0xdd} + // transfer(address,uint256) + TransferSelector = [4]byte{0xa9, 0x05, 0x9c, 0xbb} + // transferFrom(address,address,uint256) + TransferFromSelector = [4]byte{0x23, 0xb8, 0x72, 0xdd} +) + +// Big endian integer versions of function selectors +const ( + BalanceOfID = 1889567281 + DecimalsID = 826074471 + NameID = 117300739 + SymbolID = 2514000705 + TotalSupplyID = 404098525 + TransferID = 2835717307 + TransferFromID = 599290589 +) + +var _ abi.Method = (*BalanceOfCall)(nil) + +const BalanceOfCallStaticSize = 32 + +var _ abi.Tuple = (*BalanceOfCall)(nil) + +// BalanceOfCall represents an ABI tuple +type BalanceOfCall struct { + Account common.Address +} + +// EncodedSize returns the total encoded size of BalanceOfCall +func (t BalanceOfCall) EncodedSize() int { + dynamicSize := 0 + + return BalanceOfCallStaticSize + dynamicSize +} + +// EncodeTo encodes BalanceOfCall to ABI bytes in the provided buffer +func (value BalanceOfCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalanceOfCallStaticSize // Start dynamic data after static section + // Field Account: address + if _, err := abi.EncodeAddress(value.Account, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes BalanceOfCall to ABI bytes +func (value BalanceOfCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes BalanceOfCall from ABI bytes in the provided buffer +func (t *BalanceOfCall) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Account: address + t.Account, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t BalanceOfCall) GetMethodName() string { + return "balanceOf" +} + +// GetMethodID returns the function id +func (t BalanceOfCall) GetMethodID() uint32 { + return BalanceOfID +} + +// GetMethodSelector returns the function selector +func (t BalanceOfCall) GetMethodSelector() [4]byte { + return BalanceOfSelector +} + +// EncodeWithSelector encodes balanceOf arguments to ABI bytes including function selector +func (t BalanceOfCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], BalanceOfSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewBalanceOfCall constructs a new BalanceOfCall +func NewBalanceOfCall( + account common.Address, +) *BalanceOfCall { + return &BalanceOfCall{ + Account: account, + } +} + +const BalanceOfReturnStaticSize = 32 + +var _ abi.Tuple = (*BalanceOfReturn)(nil) + +// BalanceOfReturn represents an ABI tuple +type BalanceOfReturn struct { + Balance *big.Int +} + +// EncodedSize returns the total encoded size of BalanceOfReturn +func (t BalanceOfReturn) EncodedSize() int { + dynamicSize := 0 + + return BalanceOfReturnStaticSize + dynamicSize +} + +// EncodeTo encodes BalanceOfReturn to ABI bytes in the provided buffer +func (value BalanceOfReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := BalanceOfReturnStaticSize // Start dynamic data after static section + // Field Balance: uint256 + if _, err := abi.EncodeUint256(value.Balance, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes BalanceOfReturn to ABI bytes +func (value BalanceOfReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes BalanceOfReturn from ABI bytes in the provided buffer +func (t *BalanceOfReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Balance: uint256 + t.Balance, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*DecimalsCall)(nil) + +// DecimalsCall represents the input arguments for decimals function +type DecimalsCall struct { + abi.EmptyTuple +} + +// GetMethodName returns the function name +func (t DecimalsCall) GetMethodName() string { + return "decimals" +} + +// GetMethodID returns the function id +func (t DecimalsCall) GetMethodID() uint32 { + return DecimalsID +} + +// GetMethodSelector returns the function selector +func (t DecimalsCall) GetMethodSelector() [4]byte { + return DecimalsSelector +} + +// EncodeWithSelector encodes decimals arguments to ABI bytes including function selector +func (t DecimalsCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], DecimalsSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewDecimalsCall constructs a new DecimalsCall +func NewDecimalsCall() *DecimalsCall { + return &DecimalsCall{} +} + +const DecimalsReturnStaticSize = 32 + +var _ abi.Tuple = (*DecimalsReturn)(nil) + +// DecimalsReturn represents an ABI tuple +type DecimalsReturn struct { + Decimals uint8 +} + +// EncodedSize returns the total encoded size of DecimalsReturn +func (t DecimalsReturn) EncodedSize() int { + dynamicSize := 0 + + return DecimalsReturnStaticSize + dynamicSize +} + +// EncodeTo encodes DecimalsReturn to ABI bytes in the provided buffer +func (value DecimalsReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := DecimalsReturnStaticSize // Start dynamic data after static section + // Field Decimals: uint8 + if _, err := abi.EncodeUint8(value.Decimals, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes DecimalsReturn to ABI bytes +func (value DecimalsReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes DecimalsReturn from ABI bytes in the provided buffer +func (t *DecimalsReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Decimals: uint8 + t.Decimals, _, err = abi.DecodeUint8(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*NameCall)(nil) + +// NameCall represents the input arguments for name function +type NameCall struct { + abi.EmptyTuple +} + +// GetMethodName returns the function name +func (t NameCall) GetMethodName() string { + return "name" +} + +// GetMethodID returns the function id +func (t NameCall) GetMethodID() uint32 { + return NameID +} + +// GetMethodSelector returns the function selector +func (t NameCall) GetMethodSelector() [4]byte { + return NameSelector +} + +// EncodeWithSelector encodes name arguments to ABI bytes including function selector +func (t NameCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], NameSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewNameCall constructs a new NameCall +func NewNameCall() *NameCall { + return &NameCall{} +} + +const NameReturnStaticSize = 32 + +var _ abi.Tuple = (*NameReturn)(nil) + +// NameReturn represents an ABI tuple +type NameReturn struct { + Name string +} + +// EncodedSize returns the total encoded size of NameReturn +func (t NameReturn) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Name) + + return NameReturnStaticSize + dynamicSize +} + +// EncodeTo encodes NameReturn to ABI bytes in the provided buffer +func (value NameReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := NameReturnStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Name: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Name, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes NameReturn to ABI bytes +func (value NameReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes NameReturn from ABI bytes in the provided buffer +func (t *NameReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Name + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Name, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +var _ abi.Method = (*SymbolCall)(nil) + +// SymbolCall represents the input arguments for symbol function +type SymbolCall struct { + abi.EmptyTuple +} + +// GetMethodName returns the function name +func (t SymbolCall) GetMethodName() string { + return "symbol" +} + +// GetMethodID returns the function id +func (t SymbolCall) GetMethodID() uint32 { + return SymbolID +} + +// GetMethodSelector returns the function selector +func (t SymbolCall) GetMethodSelector() [4]byte { + return SymbolSelector +} + +// EncodeWithSelector encodes symbol arguments to ABI bytes including function selector +func (t SymbolCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], SymbolSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewSymbolCall constructs a new SymbolCall +func NewSymbolCall() *SymbolCall { + return &SymbolCall{} +} + +const SymbolReturnStaticSize = 32 + +var _ abi.Tuple = (*SymbolReturn)(nil) + +// SymbolReturn represents an ABI tuple +type SymbolReturn struct { + Symbol string +} + +// EncodedSize returns the total encoded size of SymbolReturn +func (t SymbolReturn) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Symbol) + + return SymbolReturnStaticSize + dynamicSize +} + +// EncodeTo encodes SymbolReturn to ABI bytes in the provided buffer +func (value SymbolReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := SymbolReturnStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Symbol: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.Symbol, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes SymbolReturn to ABI bytes +func (value SymbolReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes SymbolReturn from ABI bytes in the provided buffer +func (t *SymbolReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + offset int + ) + dynamicOffset := 32 + // Decode dynamic field Symbol + { + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } + if offset != dynamicOffset { + return 0, abi.ErrInvalidOffsetForDynamicField + } + t.Symbol, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +var _ abi.Method = (*TotalSupplyCall)(nil) + +// TotalSupplyCall represents the input arguments for totalSupply function +type TotalSupplyCall struct { + abi.EmptyTuple +} + +// GetMethodName returns the function name +func (t TotalSupplyCall) GetMethodName() string { + return "totalSupply" +} + +// GetMethodID returns the function id +func (t TotalSupplyCall) GetMethodID() uint32 { + return TotalSupplyID +} + +// GetMethodSelector returns the function selector +func (t TotalSupplyCall) GetMethodSelector() [4]byte { + return TotalSupplySelector +} + +// EncodeWithSelector encodes totalSupply arguments to ABI bytes including function selector +func (t TotalSupplyCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], TotalSupplySelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewTotalSupplyCall constructs a new TotalSupplyCall +func NewTotalSupplyCall() *TotalSupplyCall { + return &TotalSupplyCall{} +} + +const TotalSupplyReturnStaticSize = 32 + +var _ abi.Tuple = (*TotalSupplyReturn)(nil) + +// TotalSupplyReturn represents an ABI tuple +type TotalSupplyReturn struct { + Supply *big.Int +} + +// EncodedSize returns the total encoded size of TotalSupplyReturn +func (t TotalSupplyReturn) EncodedSize() int { + dynamicSize := 0 + + return TotalSupplyReturnStaticSize + dynamicSize +} + +// EncodeTo encodes TotalSupplyReturn to ABI bytes in the provided buffer +func (value TotalSupplyReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TotalSupplyReturnStaticSize // Start dynamic data after static section + // Field Supply: uint256 + if _, err := abi.EncodeUint256(value.Supply, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TotalSupplyReturn to ABI bytes +func (value TotalSupplyReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TotalSupplyReturn from ABI bytes in the provided buffer +func (t *TotalSupplyReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Supply: uint256 + t.Supply, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*TransferCall)(nil) + +const TransferCallStaticSize = 64 + +var _ abi.Tuple = (*TransferCall)(nil) + +// TransferCall represents an ABI tuple +type TransferCall struct { + To common.Address + Amount *big.Int +} + +// EncodedSize returns the total encoded size of TransferCall +func (t TransferCall) EncodedSize() int { + dynamicSize := 0 + + return TransferCallStaticSize + dynamicSize +} + +// EncodeTo encodes TransferCall to ABI bytes in the provided buffer +func (value TransferCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferCallStaticSize // Start dynamic data after static section + // Field To: address + if _, err := abi.EncodeAddress(value.To, buf[0:]); err != nil { + return 0, err + } + + // Field Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TransferCall to ABI bytes +func (value TransferCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferCall from ABI bytes in the provided buffer +func (t *TransferCall) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 64 + // Decode static field To: address + t.To, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t TransferCall) GetMethodName() string { + return "transfer" +} + +// GetMethodID returns the function id +func (t TransferCall) GetMethodID() uint32 { + return TransferID +} + +// GetMethodSelector returns the function selector +func (t TransferCall) GetMethodSelector() [4]byte { + return TransferSelector +} + +// EncodeWithSelector encodes transfer arguments to ABI bytes including function selector +func (t TransferCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], TransferSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewTransferCall constructs a new TransferCall +func NewTransferCall( + to common.Address, + amount *big.Int, +) *TransferCall { + return &TransferCall{ + To: to, + Amount: amount, + } +} + +const TransferReturnStaticSize = 32 + +var _ abi.Tuple = (*TransferReturn)(nil) + +// TransferReturn represents an ABI tuple +type TransferReturn struct { + Success bool +} + +// EncodedSize returns the total encoded size of TransferReturn +func (t TransferReturn) EncodedSize() int { + dynamicSize := 0 + + return TransferReturnStaticSize + dynamicSize +} + +// EncodeTo encodes TransferReturn to ABI bytes in the provided buffer +func (value TransferReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferReturnStaticSize // Start dynamic data after static section + // Field Success: bool + if _, err := abi.EncodeBool(value.Success, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TransferReturn to ABI bytes +func (value TransferReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferReturn from ABI bytes in the provided buffer +func (t *TransferReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Success: bool + t.Success, _, err = abi.DecodeBool(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +var _ abi.Method = (*TransferFromCall)(nil) + +const TransferFromCallStaticSize = 96 + +var _ abi.Tuple = (*TransferFromCall)(nil) + +// TransferFromCall represents an ABI tuple +type TransferFromCall struct { + From common.Address + To common.Address + Amount *big.Int +} + +// EncodedSize returns the total encoded size of TransferFromCall +func (t TransferFromCall) EncodedSize() int { + dynamicSize := 0 + + return TransferFromCallStaticSize + dynamicSize +} + +// EncodeTo encodes TransferFromCall to ABI bytes in the provided buffer +func (value TransferFromCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferFromCallStaticSize // Start dynamic data after static section + // Field From: address + if _, err := abi.EncodeAddress(value.From, buf[0:]); err != nil { + return 0, err + } + + // Field To: address + if _, err := abi.EncodeAddress(value.To, buf[32:]); err != nil { + return 0, err + } + + // Field Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[64:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TransferFromCall to ABI bytes +func (value TransferFromCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferFromCall from ABI bytes in the provided buffer +func (t *TransferFromCall) Decode(data []byte) (int, error) { + if len(data) < 96 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 96 + // Decode static field From: address + t.From, _, err = abi.DecodeAddress(data[0:]) + if err != nil { + return 0, err + } + // Decode static field To: address + t.To, _, err = abi.DecodeAddress(data[32:]) + if err != nil { + return 0, err + } + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[64:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t TransferFromCall) GetMethodName() string { + return "transferFrom" +} + +// GetMethodID returns the function id +func (t TransferFromCall) GetMethodID() uint32 { + return TransferFromID +} + +// GetMethodSelector returns the function selector +func (t TransferFromCall) GetMethodSelector() [4]byte { + return TransferFromSelector +} + +// EncodeWithSelector encodes transferFrom arguments to ABI bytes including function selector +func (t TransferFromCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], TransferFromSelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewTransferFromCall constructs a new TransferFromCall +func NewTransferFromCall( + from common.Address, + to common.Address, + amount *big.Int, +) *TransferFromCall { + return &TransferFromCall{ + From: from, + To: to, + Amount: amount, + } +} + +const TransferFromReturnStaticSize = 32 + +var _ abi.Tuple = (*TransferFromReturn)(nil) + +// TransferFromReturn represents an ABI tuple +type TransferFromReturn struct { + Success bool +} + +// EncodedSize returns the total encoded size of TransferFromReturn +func (t TransferFromReturn) EncodedSize() int { + dynamicSize := 0 + + return TransferFromReturnStaticSize + dynamicSize +} + +// EncodeTo encodes TransferFromReturn to ABI bytes in the provided buffer +func (value TransferFromReturn) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferFromReturnStaticSize // Start dynamic data after static section + // Field Success: bool + if _, err := abi.EncodeBool(value.Success, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TransferFromReturn to ABI bytes +func (value TransferFromReturn) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferFromReturn from ABI bytes in the provided buffer +func (t *TransferFromReturn) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Success: bool + t.Success, _, err = abi.DecodeBool(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// Event signatures +var ( + // Approval(address,address,uint256) + ApprovalEventTopic = common.Hash{0x8c, 0x5b, 0xe1, 0xe5, 0xeb, 0xec, 0x7d, 0x5b, 0xd1, 0x4f, 0x71, 0x42, 0x7d, 0x1e, 0x84, 0xf3, 0xdd, 0x03, 0x14, 0xc0, 0xf7, 0xb2, 0x29, 0x1e, 0x5b, 0x20, 0x0a, 0xc8, 0xc7, 0xc3, 0xb9, 0x25} + // Transfer(address,address,uint256) + TransferEventTopic = common.Hash{0xdd, 0xf2, 0x52, 0xad, 0x1b, 0xe2, 0xc8, 0x9b, 0x69, 0xc2, 0xb0, 0x68, 0xfc, 0x37, 0x8d, 0xaa, 0x95, 0x2b, 0xa7, 0xf1, 0x63, 0xc4, 0xa1, 0x16, 0x28, 0xf5, 0x5a, 0x4d, 0xf5, 0x23, 0xb3, 0xef} +) + +// ApprovalEvent represents the Approval event +var _ abi.Event = (*ApprovalEvent)(nil) + +type ApprovalEvent struct { + ApprovalEventIndexed + ApprovalEventData +} + +// NewApprovalEvent constructs a new Approval event +func NewApprovalEvent( + owner common.Address, + spender common.Address, + amount *big.Int, +) *ApprovalEvent { + return &ApprovalEvent{ + ApprovalEventIndexed: ApprovalEventIndexed{ + Owner: owner, + Spender: spender, + }, + ApprovalEventData: ApprovalEventData{ + Amount: amount, + }, + } +} + +// GetEventName returns the event name +func (e ApprovalEvent) GetEventName() string { + return "Approval" +} + +// GetEventID returns the event ID (topic) +func (e ApprovalEvent) GetEventID() common.Hash { + return ApprovalEventTopic +} + +// Approval represents an ABI event +type ApprovalEventIndexed struct { + Owner common.Address + Spender common.Address +} + +// EncodeTopics encodes indexed fields of Approval event to topics +func (e ApprovalEventIndexed) EncodeTopics() ([]common.Hash, error) { + topics := make([]common.Hash, 0, 3) + topics = append(topics, ApprovalEventTopic) + { + // Owner + var hash common.Hash + if _, err := abi.EncodeAddress(e.Owner, hash[:]); err != nil { + return nil, err + } + topics = append(topics, hash) + } + { + // Spender + var hash common.Hash + if _, err := abi.EncodeAddress(e.Spender, hash[:]); err != nil { + return nil, err + } + topics = append(topics, hash) + } + return topics, nil +} + +// DecodeTopics decodes indexed fields of Approval event from topics, ignore hash topics +func (e *ApprovalEventIndexed) DecodeTopics(topics []common.Hash) error { + if len(topics) != 3 { + return abi.ErrInvalidNumberOfTopics + } + if topics[0] != ApprovalEventTopic { + return abi.ErrInvalidEventTopic + } + var err error + e.Owner, _, err = abi.DecodeAddress(topics[1][:]) + if err != nil { + return err + } + e.Spender, _, err = abi.DecodeAddress(topics[2][:]) + if err != nil { + return err + } + return nil +} + +const ApprovalEventDataStaticSize = 32 + +var _ abi.Tuple = (*ApprovalEventData)(nil) + +// ApprovalEventData represents an ABI tuple +type ApprovalEventData struct { + Amount *big.Int +} + +// EncodedSize returns the total encoded size of ApprovalEventData +func (t ApprovalEventData) EncodedSize() int { + dynamicSize := 0 + + return ApprovalEventDataStaticSize + dynamicSize +} + +// EncodeTo encodes ApprovalEventData to ABI bytes in the provided buffer +func (value ApprovalEventData) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := ApprovalEventDataStaticSize // Start dynamic data after static section + // Field Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes ApprovalEventData to ABI bytes +func (value ApprovalEventData) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes ApprovalEventData from ABI bytes in the provided buffer +func (t *ApprovalEventData) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// TransferEvent represents the Transfer event +var _ abi.Event = (*TransferEvent)(nil) + +type TransferEvent struct { + TransferEventIndexed + TransferEventData +} + +// NewTransferEvent constructs a new Transfer event +func NewTransferEvent( + from common.Address, + to common.Address, + amount *big.Int, +) *TransferEvent { + return &TransferEvent{ + TransferEventIndexed: TransferEventIndexed{ + From: from, + To: to, + }, + TransferEventData: TransferEventData{ + Amount: amount, + }, + } +} + +// GetEventName returns the event name +func (e TransferEvent) GetEventName() string { + return "Transfer" +} + +// GetEventID returns the event ID (topic) +func (e TransferEvent) GetEventID() common.Hash { + return TransferEventTopic +} + +// Transfer represents an ABI event +type TransferEventIndexed struct { + From common.Address + To common.Address +} + +// EncodeTopics encodes indexed fields of Transfer event to topics +func (e TransferEventIndexed) EncodeTopics() ([]common.Hash, error) { + topics := make([]common.Hash, 0, 3) + topics = append(topics, TransferEventTopic) + { + // From + var hash common.Hash + if _, err := abi.EncodeAddress(e.From, hash[:]); err != nil { + return nil, err + } + topics = append(topics, hash) + } + { + // To + var hash common.Hash + if _, err := abi.EncodeAddress(e.To, hash[:]); err != nil { + return nil, err + } + topics = append(topics, hash) + } + return topics, nil +} + +// DecodeTopics decodes indexed fields of Transfer event from topics, ignore hash topics +func (e *TransferEventIndexed) DecodeTopics(topics []common.Hash) error { + if len(topics) != 3 { + return abi.ErrInvalidNumberOfTopics + } + if topics[0] != TransferEventTopic { + return abi.ErrInvalidEventTopic + } + var err error + e.From, _, err = abi.DecodeAddress(topics[1][:]) + if err != nil { + return err + } + e.To, _, err = abi.DecodeAddress(topics[2][:]) + if err != nil { + return err + } + return nil +} + +const TransferEventDataStaticSize = 32 + +var _ abi.Tuple = (*TransferEventData)(nil) + +// TransferEventData represents an ABI tuple +type TransferEventData struct { + Amount *big.Int +} + +// EncodedSize returns the total encoded size of TransferEventData +func (t TransferEventData) EncodedSize() int { + dynamicSize := 0 + + return TransferEventDataStaticSize + dynamicSize +} + +// EncodeTo encodes TransferEventData to ABI bytes in the provided buffer +func (value TransferEventData) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := TransferEventDataStaticSize // Start dynamic data after static section + // Field Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[0:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes TransferEventData to ABI bytes +func (value TransferEventData) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes TransferEventData from ABI bytes in the provided buffer +func (t *TransferEventData) Decode(data []byte) (int, error) { + if len(data) < 32 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 32 + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} diff --git a/precompiles/bank/errors.go b/precompiles/bank/errors.go new file mode 100644 index 000000000..b31f79a73 --- /dev/null +++ b/precompiles/bank/errors.go @@ -0,0 +1,8 @@ +package bank + +import "errors" + +var ( + ErrDenomNotFound = errors.New("denom not found") + ErrUnauthorized = errors.New("unauthorized") +) diff --git a/precompiles/bank/interfaces.go b/precompiles/bank/interfaces.go new file mode 100644 index 000000000..1c7de2f9e --- /dev/null +++ b/precompiles/bank/interfaces.go @@ -0,0 +1,21 @@ +package bank + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type MsgServer interface { + // Send defines a method for sending coins from one account to another account. + Send(context.Context, *banktypes.MsgSend) (*banktypes.MsgSendResponse, error) +} + +type Keeper interface { + GetSupply(ctx context.Context, denom string) sdk.Coin + GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) + GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin + IterateAccountBalances(ctx context.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) + IterateTotalSupply(ctx context.Context, cb func(sdk.Coin) bool) +} diff --git a/precompiles/bank/mock.go b/precompiles/bank/mock.go new file mode 100644 index 000000000..8ce279c86 --- /dev/null +++ b/precompiles/bank/mock.go @@ -0,0 +1,161 @@ +package bank + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" + + "github.com/cosmos/evm/x/vm/statedb" + evmtypes "github.com/cosmos/evm/x/vm/types" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type MockBankKeeper struct { + // use int64 for simplicity + balances map[string]map[string]int64 + supplies map[string]int64 + metadatas map[string]banktypes.Metadata +} + +type MockBankMsgServer struct { + keeper MockBankKeeper +} + +var ( + _ Keeper = MockBankKeeper{} + _ MsgServer = MockBankMsgServer{} +) + +func NewMockBankKeeper() MockBankKeeper { + return MockBankKeeper{ + balances: make(map[string]map[string]int64), + supplies: make(map[string]int64), + metadatas: make(map[string]banktypes.Metadata), + } +} + +func NewBankMsgServer(keeper MockBankKeeper) MockBankMsgServer { + return MockBankMsgServer{keeper} +} + +func (k MockBankKeeper) registerDenom(denom string, metadata banktypes.Metadata) { + k.metadatas[denom] = metadata +} + +func (k MockBankKeeper) mint(to sdk.AccAddress, amt sdk.Coins) { + for _, coin := range amt { + m := k.balances[string(to)] + if m == nil { + m = make(map[string]int64) + k.balances[string(to)] = m + } + amount := coin.Amount.Int64() + m[coin.Denom] += amount + k.supplies[coin.Denom] += amount + } +} + +func (k MockBankKeeper) burn(from sdk.AccAddress, amt sdk.Coins) error { + for _, coin := range amt { + amount := coin.Amount.Int64() + m, ok := k.balances[string(from)] + if !ok { + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "address: 0x%x, denom: %s, expect: %d, got: %d", from.Bytes(), coin.Denom, amount, 0) + } + available := m[coin.Denom] + if available < amount { + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "address: 0x%x, denom: %s, expect: %d, got: %d", from.Bytes(), coin.Denom, amount, available) + } + m[coin.Denom] = available - amount + k.supplies[coin.Denom] -= amount + } + return nil +} + +func (k MockBankKeeper) send(from sdk.AccAddress, to sdk.AccAddress, amt sdk.Coins) error { + if err := k.burn(from, amt); err != nil { + return err + } + k.mint(to, amt) + return nil +} + +func (k MockBankKeeper) GetSupply(ctx context.Context, denom string) sdk.Coin { + return sdk.NewCoin(denom, sdkmath.NewInt(k.supplies[denom])) +} + +func (k MockBankKeeper) GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) { + md, ok := k.metadatas[denom] + return md, ok +} + +func (k MockBankKeeper) GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin { + amount := int64(0) + if m, ok := k.balances[string(addr)]; ok { + amount = m[denom] + } + + return sdk.NewCoin(denom, sdkmath.NewInt(amount)) +} + +func (k MockBankKeeper) IterateAccountBalances(ctx context.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) { + if m, ok := k.balances[string(addr)]; ok { + for denom, amount := range m { + coin := sdk.NewCoin(denom, sdkmath.NewInt(amount)) + if cb(coin) { + break + } + } + } +} + +func (k MockBankKeeper) IterateTotalSupply(ctx context.Context, cb func(sdk.Coin) bool) { + for denom, amount := range k.supplies { + coin := sdk.NewCoin(denom, sdkmath.NewInt(amount)) + if cb(coin) { + break + } + } +} + +func (ms MockBankMsgServer) Send(goCtx context.Context, msg *banktypes.MsgSend) (*banktypes.MsgSendResponse, error) { + from, err := sdk.AccAddressFromBech32(msg.FromAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %s", err) + } + to, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + if err := ms.keeper.send(from, to, msg.Amount); err != nil { + return nil, err + } + return &banktypes.MsgSendResponse{}, nil +} + +func NewMockEVM(ctx sdk.Context) *vm.EVM { + evmKeeper := statedb.NewMockKeeper() + db := statedb.New(ctx, evmKeeper, statedb.NewEmptyTxConfig()) + blockCtx := vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + GetHash: nil, + GasLimit: 10000000, + BlockNumber: big.NewInt(1), + Time: 1, + Difficulty: big.NewInt(0), // unused. Only required in PoW context + BaseFee: big.NewInt(1000), + Random: &common.MaxHash, // need to be different than nil to signal it is after the merge and pick up the right opcodes + } + vmConfig := vm.Config{} + return vm.NewEVM(blockCtx, db, evmtypes.GetEthChainConfig(), vmConfig) +} diff --git a/precompiles/bank/query.go b/precompiles/bank/query.go index a7fc2e8f0..8aae70c67 100644 --- a/precompiles/bank/query.go +++ b/precompiles/bank/query.go @@ -1,11 +1,10 @@ package bank import ( - "fmt" + "errors" + "math" "math/big" - "github.com/ethereum/go-ethereum/accounts/abi" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -28,18 +27,12 @@ const ( // balanceOf call for each token returned. func (p Precompile) Balances( ctx sdk.Context, - method *abi.Method, - args []interface{}, -) ([]byte, error) { - account, err := ParseBalancesArgs(args) - if err != nil { - return nil, fmt.Errorf("error calling account balances in bank precompile: %s", err) - } - + args BalancesCall, +) (*BalancesReturn, error) { i := 0 balances := make([]Balance, 0) - p.bankKeeper.IterateAccountBalances(ctx, account, func(coin sdk.Coin) bool { + p.bankKeeper.IterateAccountBalances(ctx, args.Account.Bytes(), func(coin sdk.Coin) bool { defer func() { i++ }() // NOTE: we already charged for a single balanceOf request so we don't @@ -61,7 +54,7 @@ func (p Precompile) Balances( return false }) - return method.Outputs.Pack(balances) + return &BalancesReturn{balances}, nil } // TotalSupply returns the total supply of all tokens registered in the x/bank @@ -71,9 +64,8 @@ func (p Precompile) Balances( // call for each token returned. func (p Precompile) TotalSupply( ctx sdk.Context, - method *abi.Method, - _ []interface{}, -) ([]byte, error) { + args TotalSupplyCall, +) (*TotalSupplyReturn, error) { i := 0 totalSupply := make([]Balance, 0) @@ -99,7 +91,7 @@ func (p Precompile) TotalSupply( return false }) - return method.Outputs.Pack(totalSupply) + return &TotalSupplyReturn{totalSupply}, nil } // SupplyOf returns the total supply of a given registered erc20 token @@ -109,21 +101,93 @@ func (p Precompile) TotalSupply( // stored in the x/bank. func (p Precompile) SupplyOf( ctx sdk.Context, - method *abi.Method, - args []interface{}, -) ([]byte, error) { - erc20ContractAddress, err := ParseSupplyOfArgs(args) - if err != nil { - return nil, fmt.Errorf("error getting the supply in bank precompile: %s", err) - } - - tokenPairID := p.erc20Keeper.GetERC20Map(ctx, erc20ContractAddress) + args SupplyOfCall, +) (*SupplyOfReturn, error) { + tokenPairID := p.erc20Keeper.GetERC20Map(ctx, args.Contract) tokenPair, found := p.erc20Keeper.GetTokenPair(ctx, tokenPairID) if !found { - return method.Outputs.Pack(big.NewInt(0)) + return &SupplyOfReturn{big.NewInt(0)}, nil } supply := p.bankKeeper.GetSupply(ctx, tokenPair.Denom) - return method.Outputs.Pack(supply.Amount.BigInt()) + return &SupplyOfReturn{supply.Amount.BigInt()}, nil +} + +func (p Precompile) Name( + ctx sdk.Context, + args NameCall, +) (*NameReturn, error) { + metadata, found := p.bankKeeper.GetDenomMetaData(ctx, args.Denom) + if !found { + return nil, ErrDenomNotFound + } + + return &NameReturn{metadata.Name}, nil +} + +func (p Precompile) Symbol( + ctx sdk.Context, + args SymbolCall, +) (*SymbolReturn, error) { + metadata, found := p.bankKeeper.GetDenomMetaData(ctx, args.Denom) + if !found { + return nil, ErrDenomNotFound + } + + return &SymbolReturn{metadata.Symbol}, nil +} + +func (p Precompile) Decimals( + ctx sdk.Context, + args DecimalsCall, +) (*DecimalsReturn, error) { + m, found := p.bankKeeper.GetDenomMetaData(ctx, args.Denom) + if !found { + return nil, ErrDenomNotFound + } + + if len(m.DenomUnits) == 0 { + return &DecimalsReturn{0}, nil + } + + // look up Display denom unit + index := -1 + for i, denomUnit := range m.DenomUnits { + if denomUnit.Denom == m.Display { + index = i + break + } + } + + var exponent uint32 + if index == -1 { + exponent = 0 + } else { + exponent = m.DenomUnits[index].Exponent + } + + if exponent > math.MaxUint8 { + return nil, errors.New("exponent too large") + } + + return &DecimalsReturn{uint8(exponent)}, nil +} + +func (p Precompile) TotalSupplyV2( + ctx sdk.Context, + args TotalSupply0Call, +) (*TotalSupply0Return, error) { + supply := p.bankKeeper.GetSupply(ctx, args.Denom) + + return &TotalSupply0Return{supply.Amount.BigInt()}, nil +} + +func (p Precompile) BalanceOf( + ctx sdk.Context, + args BalanceOfCall, +) (*BalanceOfReturn, error) { + balance := p.bankKeeper.GetBalance(ctx, args.Account.Bytes(), args.Denom) + + return &BalanceOfReturn{balance.Amount.BigInt()}, nil } diff --git a/precompiles/bank/tx.go b/precompiles/bank/tx.go new file mode 100644 index 000000000..a097ba28b --- /dev/null +++ b/precompiles/bank/tx.go @@ -0,0 +1,50 @@ +package bank + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/core/vm" + + evmtypes "github.com/cosmos/evm/x/vm/types" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func (p Precompile) TransferFrom( + ctx sdk.Context, + args TransferFromCall, + stateDB vm.StateDB, + contract *vm.Contract, +) (*TransferFromReturn, error) { + // don't handle gas token here + if args.Denom == evmtypes.GetEVMCoinDenom() { + return nil, errors.New("cannot transfer gas token with bank precompile") + } + + // authorization: only from address or deterministic erc20 contract address can call this method + caller := contract.Caller() + erc20, err := ERC20ContractAddress(p.Address(), args.Denom) + if err != nil { + return nil, fmt.Errorf("failed to get erc20 contract address: %w", err) + } + if caller != args.From && caller != erc20 { + return nil, ErrUnauthorized + } + + coins := sdk.Coins{{Denom: args.Denom, Amount: sdkmath.NewIntFromBigInt(args.Value)}} + if err := coins.Validate(); err != nil { + return nil, fmt.Errorf("invalid coins: %w", err) + } + + // execute the transfer with bank keeper + msg := banktypes.NewMsgSend(args.From.Bytes(), args.To.Bytes(), coins) + if _, err := p.bankMsgServer.Send(ctx, msg); err != nil { + return nil, fmt.Errorf("failed to send coins: %w", err) + } + + return &TransferFromReturn{true}, nil +} diff --git a/precompiles/bank/types.go b/precompiles/bank/types.go deleted file mode 100644 index 828893b7f..000000000 --- a/precompiles/bank/types.go +++ /dev/null @@ -1,46 +0,0 @@ -package bank - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - - cmn "github.com/cosmos/evm/precompiles/common" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Balance contains the amount for a corresponding ERC-20 contract address. -type Balance struct { - ContractAddress common.Address - Amount *big.Int -} - -// ParseBalancesArgs parses the call arguments for the bank Balances query. -func ParseBalancesArgs(args []interface{}) (sdk.AccAddress, error) { - if len(args) != 1 { - return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 1, len(args)) - } - - account, ok := args[0].(common.Address) - if !ok { - return nil, fmt.Errorf(cmn.ErrInvalidType, "account", common.Address{}, args[0]) - } - - return account.Bytes(), nil -} - -// ParseSupplyOfArgs parses the call arguments for the bank SupplyOf query. -func ParseSupplyOfArgs(args []interface{}) (common.Address, error) { - if len(args) != 1 { - return common.Address{}, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 1, len(args)) - } - - erc20Address, ok := args[0].(common.Address) - if !ok { - return common.Address{}, fmt.Errorf(cmn.ErrInvalidType, "erc20Address", common.Address{}, args[0]) - } - - return erc20Address, nil -} diff --git a/precompiles/cmd/main.go b/precompiles/cmd/main.go new file mode 100644 index 000000000..8e0ca2a0e --- /dev/null +++ b/precompiles/cmd/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "flag" + "maps" + "os" + "slices" + "strings" + + "github.com/yihuang/go-abi/generator" +) + +var ( + // DefaultExtraImports adds common module to imports + DefaultExtraImports = []generator.ImportSpec{ + {Path: "github.com/cosmos/evm/precompiles/common", Alias: "cmn"}, + } + + // DefaultExternalTuples mapps common tuples definitions to common module + ExternalTuples = map[string]string{ + "Coin": "cmn.Coin", + "Dec": "cmn.Dec", + "DecCoin": "cmn.DecCoin", + "PageRequest": "cmn.PageRequest", + "PageResponse": "cmn.PageResponse", + "Height": "cmn.Height", + } +) + +func main() { + var ( + inputFile = flag.String("input", os.Getenv("GOFILE"), "Input file (JSON ABI or Go source file)") + outputFile = flag.String("output", "", "Output file") + prefix = flag.String("prefix", "", "Prefix for generated types and functions") + packageName = flag.String("package", os.Getenv("GOPACKAGE"), "Package name for generated code") + varName = flag.String("var", "", "Variable name containing human-readable ABI (for Go source files)") + extTuplesFlag = flag.String("external-tuples", "", "External tuple mappings in format 'key1=value1,key2=value2'") + imports = flag.String("imports", "", "Additional import paths, comma-separated") + stdlib = flag.Bool("stdlib", false, "Generate stdlib itself") + artifactInput = flag.Bool("artifact-input", false, "Input file is a solc artifact JSON, will extract the abi field from it") + ) + flag.Parse() + + opts := []generator.Option{ + generator.PackageName(*packageName), + generator.Prefix(*prefix), + generator.Stdlib(*stdlib), + } + + importSpecs := slices.Clone(DefaultExtraImports) + if *imports != "" { + paths := strings.Split(*imports, ",") + for _, imp := range paths { + importSpecs = append(importSpecs, generator.ParseImport(imp)) + } + } + opts = append(opts, generator.ExtraImports(importSpecs)) + + // Parse external tuples if provided + extTuples := maps.Clone(ExternalTuples) + if *extTuplesFlag != "" { + for k, v := range generator.ParseExternalTuples(*extTuplesFlag) { + extTuples[k] = v + } + } + opts = append(opts, generator.ExternalTuples(extTuples)) + + generator.Command( + *inputFile, + *varName, + *artifactInput, + *outputFile, + opts..., + ) +} diff --git a/precompiles/common/errors.go b/precompiles/common/errors.go index 2540f9732..67271775f 100644 --- a/precompiles/common/errors.go +++ b/precompiles/common/errors.go @@ -23,6 +23,8 @@ const ( ErrInvalidNumberOfArgs = "invalid number of arguments; expected %d; got: %d" // ErrUnknownMethod is raised when the method is not known. ErrUnknownMethod = "unknown method: %s" + // ErrUnknownMethodID is raised when the methodID is not known. + ErrUnknownMethodID = "unknown method id: %d" // ErrIntegerOverflow is raised when an integer overflow occurs. ErrIntegerOverflow = "integer overflow when increasing allowance" // ErrNegativeAmount is raised when an amount is negative. diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index 1554fe1b3..3ccee66f5 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -1,12 +1,14 @@ package common import ( + "encoding/binary" "errors" - "github.com/ethereum/go-ethereum/accounts/abi" + ethabi "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" + "github.com/yihuang/go-abi" "github.com/cosmos/evm/x/vm/statedb" @@ -128,11 +130,11 @@ func (p Precompile) runNativeAction(evm *vm.EVM, contract *vm.Contract, action N // SetupABI runs the initial setup required to run a transaction or a query. // It returns the ABI method, initial gas and calling arguments. func SetupABI( - api abi.ABI, + api ethabi.ABI, contract *vm.Contract, readOnly bool, - isTransaction func(name *abi.Method) bool, -) (method *abi.Method, args []interface{}, err error) { + isTransaction func(name *ethabi.Method) bool, +) (method *ethabi.Method, args []interface{}, err error) { // NOTE: This is a special case where the calling transaction does not specify a function name. // In this case we default to a `fallback` or `receive` function on the contract. @@ -165,7 +167,7 @@ func SetupABI( } // if the method type is `function` continue looking for arguments - if method.Type == abi.Function { + if method.Type == ethabi.Function { argsBz := contract.Input[4:] args, err = method.Inputs.Unpack(argsBz) if err != nil { @@ -207,7 +209,7 @@ func (p *Precompile) SetAddress(addr common.Address) { } // emptyCallData is a helper function that returns the method to be called when the calldata is empty. -func emptyCallData(api abi.ABI, contract *vm.Contract) (method *abi.Method, err error) { +func emptyCallData(api ethabi.ABI, contract *vm.Contract) (method *ethabi.Method, err error) { switch { // Case 1.1: Send call or transfer tx - 'receive' is called if present and value is transferred case contract.Value().Sign() > 0 && api.HasReceive(): @@ -222,7 +224,7 @@ func emptyCallData(api abi.ABI, contract *vm.Contract) (method *abi.Method, err } // methodIDCallData is a helper function that returns the method to be called when the calldata is less than 4 bytes. -func methodIDCallData(api abi.ABI) (method *abi.Method, err error) { +func methodIDCallData(api ethabi.ABI) (method *ethabi.Method, err error) { // Case 2.2: calldata contains less than 4 bytes needed for a method and 'fallback' is not present - return error if !api.HasFallback() { return nil, vm.ErrExecutionReverted @@ -232,7 +234,7 @@ func methodIDCallData(api abi.ABI) (method *abi.Method, err error) { } // standardCallData is a helper function that returns the method to be called when the calldata is 4 bytes or more. -func standardCallData(api abi.ABI, contract *vm.Contract) (method *abi.Method, err error) { +func standardCallData(api ethabi.ABI, contract *vm.Contract) (method *ethabi.Method, err error) { methodID := contract.Input[:4] // NOTE: this function iterates over the method map and returns // the method with the given ID @@ -250,3 +252,71 @@ func standardCallData(api abi.ABI, contract *vm.Contract) (method *abi.Method, e return method, nil } + +// SplitMethodID splits the method id from the input data. +func SplitMethodID(input []byte) (uint32, []byte, error) { + if len(input) < 4 { + return 0, nil, errors.New("invalid input length") + } + + methodID := binary.BigEndian.Uint32(input) + return methodID, input[4:], nil +} + +// ParseMethod splits method id, and check if it's allowed in readOnly mode. +func ParseMethod(input []byte, readOnly bool, isTransaction func(uint32) bool) (uint32, []byte, error) { + methodID, input, err := SplitMethodID(input) + if err != nil { + return 0, nil, err + } + + if readOnly && isTransaction(methodID) { + return 0, nil, vm.ErrWriteProtection + } + + return methodID, input, nil +} + +func Run[I any, PI interface { + *I + abi.Decode +}, O abi.Encode]( + ctx sdk.Context, + fn func(sdk.Context, I) (O, error), + input []byte, +) ([]byte, error) { + var in I + if _, err := PI(&in).Decode(input); err != nil { + return nil, err + } + + out, err := fn(ctx, in) + if err != nil { + return nil, err + } + + return out.Encode() +} + +func RunWithStateDB[I any, PI interface { + *I + abi.Decode +}, O abi.Encode]( + ctx sdk.Context, + fn func(sdk.Context, I, vm.StateDB, *vm.Contract) (O, error), + input []byte, + stateDB vm.StateDB, + contract *vm.Contract, +) ([]byte, error) { + var in I + if _, err := PI(&in).Decode(input); err != nil { + return nil, err + } + + out, err := fn(ctx, in, stateDB, contract) + if err != nil { + return nil, err + } + + return out.Encode() +} diff --git a/precompiles/types/defaults.go b/precompiles/types/defaults.go index 5d9bbd63a..824d11a23 100644 --- a/precompiles/types/defaults.go +++ b/precompiles/types/defaults.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdktypes "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" @@ -67,6 +68,7 @@ func DefaultStaticPrecompiles( stakingKeeper stakingkeeper.Keeper, distributionKeeper distributionkeeper.Keeper, bankKeeper cmn.BankKeeper, + realBankKeeper bankkeeper.Keeper, erc20Keeper *erc20Keeper.Keeper, transferKeeper *transferkeeper.Keeper, channelKeeper *channelkeeper.Keeper, @@ -76,6 +78,7 @@ func DefaultStaticPrecompiles( codec codec.Codec, opts ...Option, ) map[common.Address]vm.PrecompiledContract { + bankMsgServer := bankkeeper.NewMsgServerImpl(realBankKeeper) precompiles := NewStaticPrecompiles(). WithPraguePrecompiles(). WithP256Precompile(). @@ -84,7 +87,7 @@ func DefaultStaticPrecompiles( WithDistributionPrecompile(distributionKeeper, stakingKeeper, bankKeeper, opts...). WithICS02Precompile(codec, clientKeeper). WithICS20Precompile(bankKeeper, stakingKeeper, transferKeeper, channelKeeper). - WithBankPrecompile(bankKeeper, erc20Keeper). + WithBankPrecompile(bankMsgServer, bankKeeper, erc20Keeper). WithGovPrecompile(govKeeper, bankKeeper, codec, opts...). WithSlashingPrecompile(slashingKeeper, bankKeeper, opts...) diff --git a/precompiles/types/static_precompiles.go b/precompiles/types/static_precompiles.go index 1fcb1b038..93a667165 100644 --- a/precompiles/types/static_precompiles.go +++ b/precompiles/types/static_precompiles.go @@ -132,10 +132,11 @@ func (s StaticPrecompiles) WithICS20Precompile( } func (s StaticPrecompiles) WithBankPrecompile( + bankMsgServer bankprecompile.MsgServer, bankKeeper cmn.BankKeeper, erc20Keeper *erc20Keeper.Keeper, ) StaticPrecompiles { - bankPrecompile := bankprecompile.NewPrecompile(bankKeeper, erc20Keeper) + bankPrecompile := bankprecompile.NewPrecompile(bankMsgServer, bankprecompile.Keeper(bankKeeper), erc20Keeper) s[bankPrecompile.Address()] = bankPrecompile return s } diff --git a/rpc/namespaces/ethereum/debug/trace_fallback.go b/rpc/namespaces/ethereum/debug/trace_fallback.go index 9100dc46b..db3e8b237 100644 --- a/rpc/namespaces/ethereum/debug/trace_fallback.go +++ b/rpc/namespaces/ethereum/debug/trace_fallback.go @@ -15,7 +15,6 @@ // along with the go-ethereum library. If not, see . //go:build !go1.5 -// +build !go1.5 // no-op implementation of tracing methods for Go < 1.5. diff --git a/server/config/opendb.go b/server/config/opendb.go index af6de8dc3..1d0d99be7 100644 --- a/server/config/opendb.go +++ b/server/config/opendb.go @@ -1,5 +1,4 @@ //go:build !rocksdb -// +build !rocksdb package config diff --git a/server/config/opendb_rocksdb.go b/server/config/opendb_rocksdb.go index f81aa0271..fea6ebb95 100644 --- a/server/config/opendb_rocksdb.go +++ b/server/config/opendb_rocksdb.go @@ -1,5 +1,4 @@ //go:build rocksdb -// +build rocksdb package config @@ -8,9 +7,11 @@ import ( "runtime" "strings" + "github.com/linxGnu/grocksdb" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/server/types" - "github.com/linxGnu/grocksdb" ) // 3G block cache diff --git a/tests/integration/precompiles/bank/test_query.go b/tests/integration/precompiles/bank/test_query.go index d7dc3a0e4..178e7ea8c 100644 --- a/tests/integration/precompiles/bank/test_query.go +++ b/tests/integration/precompiles/bank/test_query.go @@ -18,43 +18,20 @@ func (s *PrecompileTestSuite) TestBalances() { var ctx sdk.Context // setup test in order to have s.precompile, s.cosmosEVMAddr and s.xmplAddr defined s.SetupTest() - method := s.precompile.Methods[bank.BalancesMethod] testcases := []struct { name string - malleate func() []interface{} + malleate func() *bank.BalancesCall expPass bool errContains string expBalances func(cosmosEVMAddr, xmplAddr common.Address) []bank.Balance }{ - { - "fail - invalid number of arguments", - func() []interface{} { - return []interface{}{ - "", "", - } - }, - false, - "invalid number of arguments", - nil, - }, - { - "fail - invalid account address", - func() []interface{} { - return []interface{}{ - "random text", - } - }, - false, - "invalid type for account", - nil, - }, { "pass - empty balances for new account", - func() []interface{} { - return []interface{}{ + func() *bank.BalancesCall { + return bank.NewBalancesCall( cosmosevmutiltx.GenerateAddress(), - } + ) }, true, "", @@ -62,10 +39,10 @@ func (s *PrecompileTestSuite) TestBalances() { }, { "pass - Initial balances present", - func() []interface{} { - return []interface{}{ + func() *bank.BalancesCall { + return bank.NewBalancesCall( s.keyring.GetAddr(0), - } + ) }, true, "", @@ -84,11 +61,11 @@ func (s *PrecompileTestSuite) TestBalances() { }, { "pass - ATOM and XMPL balances present - mint extra XMPL", - func() []interface{} { + func() *bank.BalancesCall { ctx = s.mintAndSendXMPLCoin(ctx, s.keyring.GetAccAddr(0), math.NewInt(1e18)) - return []interface{}{ + return bank.NewBalancesCall( s.keyring.GetAddr(0), - } + ) }, true, "", @@ -108,18 +85,14 @@ func (s *PrecompileTestSuite) TestBalances() { s.Run(tc.name, func() { ctx = s.SetupTest() // reset the chain each test - bz, err := s.precompile.Balances( + out, err := s.precompile.Balances( ctx, - &method, - tc.malleate(), + *tc.malleate(), ) if tc.expPass { s.Require().NoError(err) - var balances []bank.Balance - err = s.precompile.UnpackIntoInterface(&balances, method.Name, bz) - s.Require().NoError(err) - s.Require().Equal(tc.expBalances(s.cosmosEVMAddr, s.xmplAddr), balances) + s.Require().Equal(tc.expBalances(s.cosmosEVMAddr, s.xmplAddr), out.Balances) } else { s.Require().Contains(err.Error(), tc.errContains) } @@ -131,7 +104,6 @@ func (s *PrecompileTestSuite) TestTotalSupply() { var ctx sdk.Context // setup test in order to have s.precompile, s.cosmosEVMAddr and s.xmplAddr defined s.SetupTest() - method := s.precompile.Methods[bank.TotalSupplyMethod] totSupplRes, err := s.grpcHandler.GetTotalSupply() s.Require().NoError(err) @@ -164,17 +136,13 @@ func (s *PrecompileTestSuite) TestTotalSupply() { s.Run(tc.name, func() { ctx = s.SetupTest() tc.malleate() - bz, err := s.precompile.TotalSupply( + out, err := s.precompile.TotalSupply( ctx, - &method, - nil, + bank.TotalSupplyCall{}, ) s.Require().NoError(err) - var balances []bank.Balance - err = s.precompile.UnpackIntoInterface(&balances, method.Name, bz) - s.Require().NoError(err) - s.Require().Equal(tc.expSupply(s.cosmosEVMAddr, s.xmplAddr), balances) + s.Require().Equal(tc.expSupply(s.cosmosEVMAddr, s.xmplAddr), out.TotalSupply) }) } } @@ -182,7 +150,6 @@ func (s *PrecompileTestSuite) TestTotalSupply() { func (s *PrecompileTestSuite) TestSupplyOf() { // setup test in order to have s.precompile, s.cosmosEVMAddr and s.xmplAddr defined s.SetupTest() - method := s.precompile.Methods[bank.SupplyOfMethod] totSupplRes, err := s.grpcHandler.GetTotalSupply() s.Require().NoError(err) @@ -191,39 +158,17 @@ func (s *PrecompileTestSuite) TestSupplyOf() { testcases := []struct { name string - malleate func() []interface{} + malleate func() *bank.SupplyOfCall expErr bool errContains string expSupply *big.Int }{ - { - "fail - invalid number of arguments", - func() []interface{} { - return []interface{}{ - "", "", "", - } - }, - true, - "invalid number of arguments", - nil, - }, - { - "fail - invalid hex address", - func() []interface{} { - return []interface{}{ - "random text", - } - }, - true, - "invalid type for erc20Address", - nil, - }, { "pass - erc20 not registered return 0 supply", - func() []interface{} { - return []interface{}{ + func() *bank.SupplyOfCall { + return bank.NewSupplyOfCall( cosmosevmutiltx.GenerateAddress(), - } + ) }, false, "", @@ -231,10 +176,10 @@ func (s *PrecompileTestSuite) TestSupplyOf() { }, { "pass - XMPL total supply", - func() []interface{} { - return []interface{}{ + func() *bank.SupplyOfCall { + return bank.NewSupplyOfCall( s.xmplAddr, - } + ) }, false, "", @@ -243,10 +188,10 @@ func (s *PrecompileTestSuite) TestSupplyOf() { { "pass - ATOM total supply", - func() []interface{} { - return []interface{}{ + func() *bank.SupplyOfCall { + return bank.NewSupplyOfCall( s.cosmosEVMAddr, - } + ) }, false, "", @@ -258,22 +203,16 @@ func (s *PrecompileTestSuite) TestSupplyOf() { s.Run(tc.name, func() { ctx := s.SetupTest() - bz, err := s.precompile.SupplyOf( + out, err := s.precompile.SupplyOf( ctx, - &method, - tc.malleate(), + *tc.malleate(), ) if tc.expErr { s.Require().Error(err) s.Require().Contains(err.Error(), tc.errContains) } else { - out, err := method.Outputs.Unpack(bz) - s.Require().NoError(err, "expected no error unpacking") - supply, ok := out[0].(*big.Int) - s.Require().True(ok, "expected output to be a big.Int") - s.Require().NoError(err) - s.Require().Equal(supply.Int64(), tc.expSupply.Int64()) + s.Require().Equal(out.TotalSupply.Int64(), tc.expSupply.Int64()) } }) } diff --git a/tests/integration/precompiles/bank/test_utils.go b/tests/integration/precompiles/bank/test_utils.go index 4f322d630..4a05b49e1 100644 --- a/tests/integration/precompiles/bank/test_utils.go +++ b/tests/integration/precompiles/bank/test_utils.go @@ -15,14 +15,18 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ) // setupBankPrecompile is a helper function to set up an instance of the Bank precompile for // a given token denomination. func (s *PrecompileTestSuite) setupBankPrecompile() *bank.Precompile { + bankKeeper := s.network.App.GetBankKeeper() + bankMsgServer := bankkeeper.NewMsgServerImpl(bankKeeper) return bank.NewPrecompile( - s.network.App.GetBankKeeper(), + bankMsgServer, + bankKeeper, *s.network.App.GetErc20Keeper(), ) } @@ -30,8 +34,11 @@ func (s *PrecompileTestSuite) setupBankPrecompile() *bank.Precompile { // setupBankPrecompile is a helper function to set up an instance of the Bank precompile for // a given token denomination. func (is *IntegrationTestSuite) setupBankPrecompile() *bank.Precompile { + bankKeeper := is.network.App.GetBankKeeper() + bankMsgServer := bankkeeper.NewMsgServerImpl(bankKeeper) return bank.NewPrecompile( - is.network.App.GetBankKeeper(), + bankMsgServer, + bankKeeper, *is.network.App.GetErc20Keeper(), ) } diff --git a/tests/speedtest/go.mod b/tests/speedtest/go.mod index df081ab33..2d478d0c8 100644 --- a/tests/speedtest/go.mod +++ b/tests/speedtest/go.mod @@ -16,7 +16,7 @@ require ( github.com/cosmos/cosmos-sdk v0.54.0-rc.1.0.20251119151455-2667feb5154b github.com/cosmos/evm v0.2.0 github.com/cosmos/evm/evmd v0.0.0-20251112193856-d450ea1d6bd0 - github.com/ethereum/go-ethereum v1.16.5 + github.com/ethereum/go-ethereum v1.16.7 github.com/spf13/cobra v1.10.1 ) @@ -240,6 +240,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yihuang/go-abi v0.1.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect diff --git a/tests/speedtest/go.sum b/tests/speedtest/go.sum index 0065fd841..57496affa 100644 --- a/tests/speedtest/go.sum +++ b/tests/speedtest/go.sum @@ -951,6 +951,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA= github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -984,6 +986,8 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yihuang/go-abi v0.1.1 h1:5MHV/wOz0wywsb9IhaZmHLhBNAF5EzSXisPyv3gN5Rs= +github.com/yihuang/go-abi v0.1.1/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 5c7a8aca6..4a1432e22 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -8,7 +8,7 @@ require ( github.com/cometbft/cometbft v0.39.0-beta.2 github.com/cosmos/cosmos-sdk v0.54.0-beta.0 github.com/cosmos/evm v0.5.0-rc.0 - github.com/ethereum/go-ethereum v1.16.5 + github.com/ethereum/go-ethereum v1.16.7 github.com/holiman/uint256 v1.3.2 github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.38.0 diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index d6f7c1c7a..6b1401ffc 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -911,6 +911,8 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yihuang/go-abi v0.1.1 h1:5MHV/wOz0wywsb9IhaZmHLhBNAF5EzSXisPyv3gN5Rs= +github.com/yihuang/go-abi v0.1.1/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= diff --git a/x/vm/statedb/mock_test.go b/x/vm/statedb/mockkeeper.go similarity index 90% rename from x/vm/statedb/mock_test.go rename to x/vm/statedb/mockkeeper.go index fc6647a68..499967048 100644 --- a/x/vm/statedb/mock_test.go +++ b/x/vm/statedb/mockkeeper.go @@ -1,4 +1,4 @@ -package statedb_test +package statedb import ( "errors" @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/cosmos/evm/x/vm/statedb" "github.com/cosmos/evm/x/vm/types" storetypes "cosmossdk.io/store/types" @@ -16,13 +15,13 @@ import ( ) var ( - _ statedb.Keeper = &MockKeeper{} + _ Keeper = &MockKeeper{} errAddress common.Address = common.BigToAddress(big.NewInt(100)) ) type MockAcount struct { - account statedb.Account - states statedb.Storage + account Account + states Storage } type MockKeeper struct { @@ -41,7 +40,7 @@ func NewMockKeeper() *MockKeeper { } } -func (k MockKeeper) GetAccount(_ sdk.Context, addr common.Address) *statedb.Account { +func (k MockKeeper) GetAccount(_ sdk.Context, addr common.Address) *Account { acct, ok := k.accounts[addr] if !ok { return nil @@ -67,7 +66,7 @@ func (k MockKeeper) ForEachStorage(_ sdk.Context, addr common.Address, cb func(k } } -func (k MockKeeper) SetAccount(_ sdk.Context, addr common.Address, account statedb.Account) error { +func (k MockKeeper) SetAccount(_ sdk.Context, addr common.Address, account Account) error { if addr == errAddress { return errors.New("mock db error") } @@ -77,7 +76,7 @@ func (k MockKeeper) SetAccount(_ sdk.Context, addr common.Address, account state acct.account = account k.accounts[addr] = acct } else { - k.accounts[addr] = MockAcount{account: account, states: make(statedb.Storage)} + k.accounts[addr] = MockAcount{account: account, states: make(Storage)} } return nil } diff --git a/x/vm/types/config.go b/x/vm/types/config.go index 4fc952a76..a8bbb9f18 100644 --- a/x/vm/types/config.go +++ b/x/vm/types/config.go @@ -3,7 +3,6 @@ // Its primary purpose is to be used during application initialization. //go:build !test -// +build !test package types diff --git a/x/vm/types/config_testing.go b/x/vm/types/config_testing.go index c84440aca..d955a181e 100644 --- a/x/vm/types/config_testing.go +++ b/x/vm/types/config_testing.go @@ -3,7 +3,6 @@ // Its primary purpose is to be used during application initialization. //go:build test -// +build test package types diff --git a/x/vm/types/denom_config.go b/x/vm/types/denom_config.go index e3f0fac5b..873f38215 100644 --- a/x/vm/types/denom_config.go +++ b/x/vm/types/denom_config.go @@ -3,7 +3,6 @@ // Its primary purpose is to be used during application initialization. //go:build !test -// +build !test package types diff --git a/x/vm/types/denom_config_testing.go b/x/vm/types/denom_config_testing.go index 9e731d7db..aca9cdbf8 100644 --- a/x/vm/types/denom_config_testing.go +++ b/x/vm/types/denom_config_testing.go @@ -3,7 +3,6 @@ // Its primary purpose is to be used during application initialization. //go:build test -// +build test package types