From ae68f8f9e2d597e8a07e9949a2f4ac561ca148d8 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 5 Nov 2025 22:03:57 +0800 Subject: [PATCH 01/14] feat: redesign bank precompile for erc20 support Closes: #505 Supersedes: #517 Use go-abi to simplify implementation. update erc20 source --- evmd/app.go | 1 + evmd/go.mod | 3 +- evmd/go.sum | 4 + go.mod | 7 +- go.sum | 12 +- precompiles/bank/ERC20.bin | 1 + precompiles/bank/ERC20.sol | 114 ++ precompiles/bank/bank.abi.go | 1770 +++++++++++++++++++++++ precompiles/bank/bank.go | 125 +- precompiles/bank/erc20.go | 41 + precompiles/bank/errors.go | 8 + precompiles/bank/query.go | 128 +- precompiles/bank/tx.go | 48 + precompiles/bank/types.go | 7 - precompiles/cmd/main.go | 75 + precompiles/common/abi.go | 16 + precompiles/common/common.abi.go | 1009 +++++++++++++ precompiles/common/errors.go | 2 + precompiles/common/interfaces.go | 5 + precompiles/common/precompile.go | 86 +- precompiles/common/types.go | 76 +- precompiles/types/defaults.go | 5 +- precompiles/types/static_precompiles.go | 3 +- 23 files changed, 3398 insertions(+), 148 deletions(-) create mode 100644 precompiles/bank/ERC20.bin create mode 100644 precompiles/bank/ERC20.sol create mode 100644 precompiles/bank/bank.abi.go create mode 100644 precompiles/bank/erc20.go create mode 100644 precompiles/bank/errors.go create mode 100644 precompiles/bank/tx.go create mode 100644 precompiles/cmd/main.go create mode 100644 precompiles/common/common.abi.go diff --git a/evmd/app.go b/evmd/app.go index 09634151d..8a4428a6a 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 557603085..6a4ebcb79 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 @@ -241,6 +241,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.0.0-20251105152715-7472843b6ae6 // 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 d00ea3ccf..0cae54ad4 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.0.0-20251105152715-7472843b6ae6 h1:WPjvbj0+yTLpc2PQSxhZuRh9P4prPUQHS7Ap43EO3Zk= +github.com/yihuang/go-abi v0.0.0-20251105152715-7472843b6ae6/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 58bf5a228..9ccdefc7f 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.0.0-20251105152715-7472843b6ae6 github.com/zondax/hid v0.9.2 go.uber.org/mock v0.6.0 golang.org/x/crypto v0.43.0 @@ -109,7 +110,6 @@ require ( github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/chigopher/pathlib v0.19.1 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect @@ -184,12 +184,10 @@ require ( github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huandu/skiplist v1.2.1 // indirect - github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jinzhu/copier v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect @@ -246,7 +244,6 @@ require ( github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect - github.com/vektra/mockery/v2 v2.53.5 // 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/go.sum b/go.sum index 2a25ff548..1e706a315 100644 --- a/go.sum +++ b/go.sum @@ -204,8 +204,6 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chigopher/pathlib v0.19.1 h1:RoLlUJc0CqBGwq239cilyhxPNLXTK+HXoASGyGznx5A= -github.com/chigopher/pathlib v0.19.1/go.mod h1:tzC1dZLW8o33UQpWkNkhvPwL5n4yyFRFm/jL1YGWFvY= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -602,8 +600,6 @@ github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3 github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w= github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -627,8 +623,6 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= -github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= -github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= @@ -958,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= @@ -985,11 +981,11 @@ github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= -github.com/vektra/mockery/v2 v2.53.5 h1:iktAY68pNiMvLoHxKqlSNSv/1py0QF/17UGrrAMYDI8= -github.com/vektra/mockery/v2 v2.53.5/go.mod h1:hIFFb3CvzPdDJJiU7J4zLRblUMv7OuezWsHPmswriwo= 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.0.0-20251105152715-7472843b6ae6 h1:WPjvbj0+yTLpc2PQSxhZuRh9P4prPUQHS7Ap43EO3Zk= +github.com/yihuang/go-abi v0.0.0-20251105152715-7472843b6ae6/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/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..0f94eb6e5 --- /dev/null +++ b/precompiles/bank/bank.abi.go @@ -0,0 +1,1770 @@ +// Code generated by go-abi. DO NOT EDIT. + +package bank + +import ( + "encoding/binary" + "errors" + "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 { + Contract 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 Contract: address + if _, err := abi.EncodeAddress(value.Contract, 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 Contract: address + t.Contract, _, 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 + length := int(binary.BigEndian.Uint64(data[24:32])) + if len(data) < 32 { + return nil, 0, io.ErrUnexpectedEOF + } + data = data[32:] + if len(data) < 64*length { + return nil, 0, io.ErrUnexpectedEOF + } + var ( + n int + err error + 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 + ) + 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 := int(binary.BigEndian.Uint64(data[32+24 : 32+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Balances + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Balances") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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 + ) + dynamicOffset := 64 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Name + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Name") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Symbol + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Symbol") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field TotalSupply + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field TotalSupply") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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 + ) + 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 := int(binary.BigEndian.Uint64(data[96+24 : 96+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + 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..510e9e9c0 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -6,7 +6,6 @@ package bank import ( - "bytes" "fmt" "github.com/ethereum/go-ethereum/accounts/abi" @@ -23,6 +22,27 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +//go:generate go run ../cmd -var=ABI -output bank.abi.go + +var ABI = []string{ + // backwards compatibility + "struct Balance{ address contract; 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) external 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 contractor abi + "function erc20ctor(string denom, address bank)", +} + const ( // GasBalances defines the gas cost for a single ERC-20 balanceOf query GasBalances = 2_851 @@ -32,38 +52,25 @@ const ( // GasSupplyOf defines the gas cost for a single ERC-20 supplyOf query, taken from totalSupply of ERC20 GasSupplyOf = 2_477 -) - -var _ vm.PrecompiledContract = &Precompile{} -var ( - // Embed abi json file to the executable binary. Needed when importing as dependency. - // - //go:embed abi.json - f []byte - ABI abi.ABI + TransferFromMethod = "transferFrom" ) -func init() { - var err error - ABI, err = abi.JSON(bytes.NewReader(f)) - if err != nil { - panic(err) - } -} +var _ vm.PrecompiledContract = &Precompile{} // Precompile defines the bank precompile type Precompile struct { cmn.Precompile - abi.ABI - bankKeeper cmn.BankKeeper - erc20Keeper cmn.ERC20Keeper + bankMsgServer cmn.BankMsgServer + bankKeeper cmn.BankKeeper + erc20Keeper cmn.ERC20Keeper } // NewPrecompile creates a new bank Precompile instance implementing the // PrecompiledContract interface. func NewPrecompile( + bankMsgServer cmn.BankMsgServer, bankKeeper cmn.BankKeeper, erc20Keeper cmn.ERC20Keeper, ) *Precompile { @@ -75,70 +82,82 @@ func NewPrecompile( TransientKVGasConfig: storetypes.GasConfig{}, ContractAddress: common.HexToAddress(evmtypes.BankPrecompileAddress), }, - ABI: ABI, - bankKeeper: bankKeeper, - erc20Keeper: erc20Keeper, + 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(_ *abi.Method) bool { - return false +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) IsTransactionID(methodID uint32) bool { + return methodID == TransferFromID } diff --git a/precompiles/bank/erc20.go b/precompiles/bank/erc20.go new file mode 100644 index 000000000..e144dcbfc --- /dev/null +++ b/precompiles/bank/erc20.go @@ -0,0 +1,41 @@ +package bank + +import ( + _ "embed" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +// 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/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/query.go b/precompiles/bank/query.go index a7fc2e8f0..932edf8ee 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 @@ -54,14 +47,14 @@ func (p Precompile) Balances( } balances = append(balances, Balance{ - ContractAddress: contractAddress, - Amount: coin.Amount.BigInt(), + Contract: contractAddress, + Amount: coin.Amount.BigInt(), }) 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) @@ -92,14 +84,14 @@ func (p Precompile) TotalSupply( } totalSupply = append(totalSupply, Balance{ - ContractAddress: contractAddress, - Amount: coin.Amount.BigInt(), + Contract: contractAddress, + Amount: coin.Amount.BigInt(), }) 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..87b3b8ad2 --- /dev/null +++ b/precompiles/bank/tx.go @@ -0,0 +1,48 @@ +package bank + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/core/vm" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + evmtypes "github.com/cosmos/evm/x/vm/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 index 828893b7f..6b8e189bb 100644 --- a/precompiles/bank/types.go +++ b/precompiles/bank/types.go @@ -2,7 +2,6 @@ package bank import ( "fmt" - "math/big" "github.com/ethereum/go-ethereum/common" @@ -11,12 +10,6 @@ import ( 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 { 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/abi.go b/precompiles/common/abi.go index e451f93d7..d62b6a79b 100644 --- a/precompiles/common/abi.go +++ b/precompiles/common/abi.go @@ -12,6 +12,22 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) +//go:generate go run github.com/yihuang/go-abi/cmd -var=CommonABI -output common.abi.go + +var CommonABI = []string{ + "struct Coin {string denom; uint256 amount;}", + "struct DecCoin {string denom; uint256 amount; uint8 precision;}", + "struct Dec {uint256 value; uint8 precision;}", + "struct Height { uint64 revisionNumber; uint64 revisionHeight; }", + "struct PageRequest { bytes key; uint64 offset; uint64 limit; bool countTotal; bool reverse; }", + "struct PageResponse { bytes nextKey; uint64 total; }", + "struct ICS20Allocation { string sourcePort; string sourceChannel; Coin[] spendLimit; string[] allowList; string[] allowedPacketData; }", + + // there's no dedicated tyeps for structs in ABI, + // the dummy function to keep them in the ABI + "function dummy(Coin a, DecCoin b, Dec c, Height d, PageRequest e, PageResponse f, ICS20Allocation g)", +} + // MakeTopic converts a filter query argument into a filter topic. // NOTE: This was copied from accounts/abi/topics.go func MakeTopic(rule interface{}) (common.Hash, error) { diff --git a/precompiles/common/common.abi.go b/precompiles/common/common.abi.go new file mode 100644 index 000000000..eebfe6500 --- /dev/null +++ b/precompiles/common/common.abi.go @@ -0,0 +1,1009 @@ +// Code generated by go-abi. DO NOT EDIT. + +package common + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + + "github.com/yihuang/go-abi" +) + +// Function selectors +var ( + // dummy((string,uint256),(string,uint256,uint8),(uint256,uint8),(uint64,uint64),(bytes,uint64,uint64,bool,bool),(bytes,uint64),(string,string,(string,uint256)[],string[],string[])) + DummySelector = [4]byte{0x59, 0xd4, 0xfe, 0x1a} +) + +// Big endian integer versions of function selectors +const ( + DummyID = 1507130906 +) + +const CoinStaticSize = 64 + +var _ abi.Tuple = (*Coin)(nil) + +// Coin represents an ABI tuple +type Coin struct { + Denom string + Amount *big.Int +} + +// EncodedSize returns the total encoded size of Coin +func (t Coin) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return CoinStaticSize + dynamicSize +} + +// EncodeTo encodes Coin to ABI bytes in the provided buffer +func (value Coin) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := CoinStaticSize // 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 Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes Coin to ABI bytes +func (value Coin) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes Coin from ABI bytes in the provided buffer +func (t *Coin) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + ) + dynamicOffset := 64 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +const DecStaticSize = 64 + +var _ abi.Tuple = (*Dec)(nil) + +// Dec represents an ABI tuple +type Dec struct { + Value *big.Int + Precision uint8 +} + +// EncodedSize returns the total encoded size of Dec +func (t Dec) EncodedSize() int { + dynamicSize := 0 + + return DecStaticSize + dynamicSize +} + +// EncodeTo encodes Dec to ABI bytes in the provided buffer +func (value Dec) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := DecStaticSize // Start dynamic data after static section + // Field Value: uint256 + if _, err := abi.EncodeUint256(value.Value, buf[0:]); err != nil { + return 0, err + } + + // Field Precision: uint8 + if _, err := abi.EncodeUint8(value.Precision, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes Dec to ABI bytes +func (value Dec) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes Dec from ABI bytes in the provided buffer +func (t *Dec) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 64 + // Decode static field Value: uint256 + t.Value, _, err = abi.DecodeUint256(data[0:]) + if err != nil { + return 0, err + } + // Decode static field Precision: uint8 + t.Precision, _, err = abi.DecodeUint8(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +const DecCoinStaticSize = 96 + +var _ abi.Tuple = (*DecCoin)(nil) + +// DecCoin represents an ABI tuple +type DecCoin struct { + Denom string + Amount *big.Int + Precision uint8 +} + +// EncodedSize returns the total encoded size of DecCoin +func (t DecCoin) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.Denom) + + return DecCoinStaticSize + dynamicSize +} + +// EncodeTo encodes DecCoin to ABI bytes in the provided buffer +func (value DecCoin) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := DecCoinStaticSize // 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 Amount: uint256 + if _, err := abi.EncodeUint256(value.Amount, buf[32:]); err != nil { + return 0, err + } + + // Field Precision: uint8 + if _, err := abi.EncodeUint8(value.Precision, buf[64:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes DecCoin to ABI bytes +func (value DecCoin) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes DecCoin from ABI bytes in the provided buffer +func (t *DecCoin) Decode(data []byte) (int, error) { + if len(data) < 96 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + ) + dynamicOffset := 96 + // Decode dynamic field Denom + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Denom") + } + t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode static field Amount: uint256 + t.Amount, _, err = abi.DecodeUint256(data[32:]) + if err != nil { + return 0, err + } + // Decode static field Precision: uint8 + t.Precision, _, err = abi.DecodeUint8(data[64:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +const HeightStaticSize = 64 + +var _ abi.Tuple = (*Height)(nil) + +// Height represents an ABI tuple +type Height struct { + RevisionNumber uint64 + RevisionHeight uint64 +} + +// EncodedSize returns the total encoded size of Height +func (t Height) EncodedSize() int { + dynamicSize := 0 + + return HeightStaticSize + dynamicSize +} + +// EncodeTo encodes Height to ABI bytes in the provided buffer +func (value Height) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := HeightStaticSize // Start dynamic data after static section + // Field RevisionNumber: uint64 + if _, err := abi.EncodeUint64(value.RevisionNumber, buf[0:]); err != nil { + return 0, err + } + + // Field RevisionHeight: uint64 + if _, err := abi.EncodeUint64(value.RevisionHeight, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes Height to ABI bytes +func (value Height) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes Height from ABI bytes in the provided buffer +func (t *Height) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + ) + dynamicOffset := 64 + // Decode static field RevisionNumber: uint64 + t.RevisionNumber, _, err = abi.DecodeUint64(data[0:]) + if err != nil { + return 0, err + } + // Decode static field RevisionHeight: uint64 + t.RevisionHeight, _, err = abi.DecodeUint64(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +const ICS20AllocationStaticSize = 160 + +var _ abi.Tuple = (*ICS20Allocation)(nil) + +// ICS20Allocation represents an ABI tuple +type ICS20Allocation struct { + SourcePort string + SourceChannel string + SpendLimit []Coin + AllowList []string + AllowedPacketData []string +} + +// EncodedSize returns the total encoded size of ICS20Allocation +func (t ICS20Allocation) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeString(t.SourcePort) + dynamicSize += abi.SizeString(t.SourceChannel) + dynamicSize += SizeCoinSlice(t.SpendLimit) + dynamicSize += abi.SizeStringSlice(t.AllowList) + dynamicSize += abi.SizeStringSlice(t.AllowedPacketData) + + return ICS20AllocationStaticSize + dynamicSize +} + +// EncodeTo encodes ICS20Allocation to ABI bytes in the provided buffer +func (value ICS20Allocation) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := ICS20AllocationStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field SourcePort: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.SourcePort, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field SourceChannel: string + // Encode offset pointer + binary.BigEndian.PutUint64(buf[32+24:32+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeString(value.SourceChannel, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field SpendLimit: (string,uint256)[] + // Encode offset pointer + binary.BigEndian.PutUint64(buf[64+24:64+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = EncodeCoinSlice(value.SpendLimit, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field AllowList: string[] + // Encode offset pointer + binary.BigEndian.PutUint64(buf[96+24:96+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeStringSlice(value.AllowList, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field AllowedPacketData: string[] + // Encode offset pointer + binary.BigEndian.PutUint64(buf[128+24:128+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeStringSlice(value.AllowedPacketData, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes ICS20Allocation to ABI bytes +func (value ICS20Allocation) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes ICS20Allocation from ABI bytes in the provided buffer +func (t *ICS20Allocation) Decode(data []byte) (int, error) { + if len(data) < 160 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + ) + dynamicOffset := 160 + // Decode dynamic field SourcePort + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field SourcePort") + } + t.SourcePort, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field SourceChannel + { + offset := int(binary.BigEndian.Uint64(data[32+24 : 32+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field SourceChannel") + } + t.SourceChannel, n, err = abi.DecodeString(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field SpendLimit + { + offset := int(binary.BigEndian.Uint64(data[64+24 : 64+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field SpendLimit") + } + t.SpendLimit, n, err = DecodeCoinSlice(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field AllowList + { + offset := int(binary.BigEndian.Uint64(data[96+24 : 96+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field AllowList") + } + t.AllowList, n, err = abi.DecodeStringSlice(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field AllowedPacketData + { + offset := int(binary.BigEndian.Uint64(data[128+24 : 128+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field AllowedPacketData") + } + t.AllowedPacketData, n, err = abi.DecodeStringSlice(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +const PageRequestStaticSize = 160 + +var _ abi.Tuple = (*PageRequest)(nil) + +// PageRequest represents an ABI tuple +type PageRequest struct { + Key []byte + Offset uint64 + Limit uint64 + CountTotal bool + Reverse bool +} + +// EncodedSize returns the total encoded size of PageRequest +func (t PageRequest) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeBytes(t.Key) + + return PageRequestStaticSize + dynamicSize +} + +// EncodeTo encodes PageRequest to ABI bytes in the provided buffer +func (value PageRequest) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := PageRequestStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field Key: bytes + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeBytes(value.Key, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field Offset: uint64 + if _, err := abi.EncodeUint64(value.Offset, buf[32:]); err != nil { + return 0, err + } + + // Field Limit: uint64 + if _, err := abi.EncodeUint64(value.Limit, buf[64:]); err != nil { + return 0, err + } + + // Field CountTotal: bool + if _, err := abi.EncodeBool(value.CountTotal, buf[96:]); err != nil { + return 0, err + } + + // Field Reverse: bool + if _, err := abi.EncodeBool(value.Reverse, buf[128:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes PageRequest to ABI bytes +func (value PageRequest) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes PageRequest from ABI bytes in the provided buffer +func (t *PageRequest) Decode(data []byte) (int, error) { + if len(data) < 160 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + ) + dynamicOffset := 160 + // Decode dynamic field Key + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Key") + } + t.Key, n, err = abi.DecodeBytes(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode static field Offset: uint64 + t.Offset, _, err = abi.DecodeUint64(data[32:]) + if err != nil { + return 0, err + } + // Decode static field Limit: uint64 + t.Limit, _, err = abi.DecodeUint64(data[64:]) + if err != nil { + return 0, err + } + // Decode static field CountTotal: bool + t.CountTotal, _, err = abi.DecodeBool(data[96:]) + if err != nil { + return 0, err + } + // Decode static field Reverse: bool + t.Reverse, _, err = abi.DecodeBool(data[128:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +const PageResponseStaticSize = 64 + +var _ abi.Tuple = (*PageResponse)(nil) + +// PageResponse represents an ABI tuple +type PageResponse struct { + NextKey []byte + Total uint64 +} + +// EncodedSize returns the total encoded size of PageResponse +func (t PageResponse) EncodedSize() int { + dynamicSize := 0 + dynamicSize += abi.SizeBytes(t.NextKey) + + return PageResponseStaticSize + dynamicSize +} + +// EncodeTo encodes PageResponse to ABI bytes in the provided buffer +func (value PageResponse) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := PageResponseStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field NextKey: bytes + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = abi.EncodeBytes(value.NextKey, buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field Total: uint64 + if _, err := abi.EncodeUint64(value.Total, buf[32:]); err != nil { + return 0, err + } + + return dynamicOffset, nil +} + +// Encode encodes PageResponse to ABI bytes +func (value PageResponse) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes PageResponse from ABI bytes in the provided buffer +func (t *PageResponse) Decode(data []byte) (int, error) { + if len(data) < 64 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + ) + dynamicOffset := 64 + // Decode dynamic field NextKey + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field NextKey") + } + t.NextKey, n, err = abi.DecodeBytes(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode static field Total: uint64 + t.Total, _, err = abi.DecodeUint64(data[32:]) + if err != nil { + return 0, err + } + return dynamicOffset, nil +} + +// EncodeCoinSlice encodes (string,uint256)[] to ABI bytes +func EncodeCoinSlice(value []Coin, buf []byte) (int, error) { + // Encode length + binary.BigEndian.PutUint64(buf[24:32], uint64(len(value))) + buf = buf[32:] + + // Encode elements with dynamic types + var offset int + dynamicOffset := len(value) * 32 + for _, elem := range value { + // Write offset for element + offset += 32 + binary.BigEndian.PutUint64(buf[offset-8:offset], uint64(dynamicOffset)) + + // Write element at dynamic region + n, err := elem.EncodeTo(buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + + return dynamicOffset + 32, nil +} + +// SizeCoinSlice returns the encoded size of (string,uint256)[] +func SizeCoinSlice(value []Coin) int { + size := 32 + 32*len(value) // length + offset pointers for dynamic elements + for _, elem := range value { + size += elem.EncodedSize() + } + return size +} + +// DecodeCoinSlice decodes (string,uint256)[] from ABI bytes +func DecodeCoinSlice(data []byte) ([]Coin, int, error) { + // Decode length + length := int(binary.BigEndian.Uint64(data[24:32])) + if len(data) < 32 { + return nil, 0, io.ErrUnexpectedEOF + } + data = data[32:] + if len(data) < 32*length { + return nil, 0, io.ErrUnexpectedEOF + } + var ( + n int + err error + offset int + ) + // Decode elements with dynamic types + result := make([]Coin, length) + dynamicOffset := length * 32 + for i := 0; i < length; i++ { + offset += 32 + tmp := int(binary.BigEndian.Uint64(data[offset-8 : offset])) + if dynamicOffset != tmp { + return nil, 0, fmt.Errorf("invalid offset for slice element %d: expected %d, got %d", i, dynamicOffset, tmp) + } + n, err = result[i].Decode(data[dynamicOffset:]) + if err != nil { + return nil, 0, err + } + dynamicOffset += n + } + return result, dynamicOffset + 32, nil +} + +var _ abi.Method = (*DummyCall)(nil) + +const DummyCallStaticSize = 288 + +var _ abi.Tuple = (*DummyCall)(nil) + +// DummyCall represents an ABI tuple +type DummyCall struct { + A Coin + B DecCoin + C Dec + D Height + E PageRequest + F PageResponse + G ICS20Allocation +} + +// EncodedSize returns the total encoded size of DummyCall +func (t DummyCall) EncodedSize() int { + dynamicSize := 0 + dynamicSize += t.A.EncodedSize() + dynamicSize += t.B.EncodedSize() + dynamicSize += t.E.EncodedSize() + dynamicSize += t.F.EncodedSize() + dynamicSize += t.G.EncodedSize() + + return DummyCallStaticSize + dynamicSize +} + +// EncodeTo encodes DummyCall to ABI bytes in the provided buffer +func (value DummyCall) EncodeTo(buf []byte) (int, error) { + // Encode tuple fields + dynamicOffset := DummyCallStaticSize // Start dynamic data after static section + var ( + err error + n int + ) + // Field A: (string,uint256) + // Encode offset pointer + binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = value.A.EncodeTo(buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field B: (string,uint256,uint8) + // Encode offset pointer + binary.BigEndian.PutUint64(buf[32+24:32+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = value.B.EncodeTo(buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field C: (uint256,uint8) + if _, err := value.C.EncodeTo(buf[64:]); err != nil { + return 0, err + } + + // Field D: (uint64,uint64) + if _, err := value.D.EncodeTo(buf[128:]); err != nil { + return 0, err + } + + // Field E: (bytes,uint64,uint64,bool,bool) + // Encode offset pointer + binary.BigEndian.PutUint64(buf[192+24:192+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = value.E.EncodeTo(buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field F: (bytes,uint64) + // Encode offset pointer + binary.BigEndian.PutUint64(buf[224+24:224+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = value.F.EncodeTo(buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + // Field G: (string,string,(string,uint256)[],string[],string[]) + // Encode offset pointer + binary.BigEndian.PutUint64(buf[256+24:256+32], uint64(dynamicOffset)) + // Encode dynamic data + n, err = value.G.EncodeTo(buf[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + + return dynamicOffset, nil +} + +// Encode encodes DummyCall to ABI bytes +func (value DummyCall) Encode() ([]byte, error) { + buf := make([]byte, value.EncodedSize()) + if _, err := value.EncodeTo(buf); err != nil { + return nil, err + } + return buf, nil +} + +// Decode decodes DummyCall from ABI bytes in the provided buffer +func (t *DummyCall) Decode(data []byte) (int, error) { + if len(data) < 288 { + return 0, io.ErrUnexpectedEOF + } + var ( + err error + n int + ) + dynamicOffset := 288 + // Decode dynamic field A + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field A") + } + n, err = t.A.Decode(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field B + { + offset := int(binary.BigEndian.Uint64(data[32+24 : 32+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field B") + } + n, err = t.B.Decode(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode static field C: (uint256,uint8) + _, err = t.C.Decode(data[64:]) + if err != nil { + return 0, err + } + // Decode static field D: (uint64,uint64) + _, err = t.D.Decode(data[128:]) + if err != nil { + return 0, err + } + // Decode dynamic field E + { + offset := int(binary.BigEndian.Uint64(data[192+24 : 192+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field E") + } + n, err = t.E.Decode(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field F + { + offset := int(binary.BigEndian.Uint64(data[224+24 : 224+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field F") + } + n, err = t.F.Decode(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + // Decode dynamic field G + { + offset := int(binary.BigEndian.Uint64(data[256+24 : 256+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field G") + } + n, err = t.G.Decode(data[dynamicOffset:]) + if err != nil { + return 0, err + } + dynamicOffset += n + } + return dynamicOffset, nil +} + +// GetMethodName returns the function name +func (t DummyCall) GetMethodName() string { + return "dummy" +} + +// GetMethodID returns the function id +func (t DummyCall) GetMethodID() uint32 { + return DummyID +} + +// GetMethodSelector returns the function selector +func (t DummyCall) GetMethodSelector() [4]byte { + return DummySelector +} + +// EncodeWithSelector encodes dummy arguments to ABI bytes including function selector +func (t DummyCall) EncodeWithSelector() ([]byte, error) { + result := make([]byte, 4+t.EncodedSize()) + copy(result[:4], DummySelector[:]) + if _, err := t.EncodeTo(result[4:]); err != nil { + return nil, err + } + return result, nil +} + +// NewDummyCall constructs a new DummyCall +func NewDummyCall( + a Coin, + b DecCoin, + c Dec, + d Height, + e PageRequest, + f PageResponse, + g ICS20Allocation, +) *DummyCall { + return &DummyCall{ + A: a, + B: b, + C: c, + D: d, + E: e, + F: f, + G: g, + } +} + +// DummyReturn represents the output arguments for dummy function +type DummyReturn struct { + abi.EmptyTuple +} 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/interfaces.go b/precompiles/common/interfaces.go index e69e11d39..c613b75c1 100644 --- a/precompiles/common/interfaces.go +++ b/precompiles/common/interfaces.go @@ -28,6 +28,11 @@ type BankKeeper interface { BlockedAddr(addr sdk.AccAddress) bool } +type BankMsgServer interface { + // Send defines a method for sending coins from one account to another account. + Send(context.Context, *banktypes.MsgSend) (*banktypes.MsgSendResponse, error) +} + type TransferKeeper interface { Denom(ctx context.Context, req *ibctypes.QueryDenomRequest) (*ibctypes.QueryDenomResponse, error) Denoms(ctx context.Context, req *ibctypes.QueryDenomsRequest) (*ibctypes.QueryDenomsResponse, error) 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/common/types.go b/precompiles/common/types.go index 4e1d568b9..5d8b97f7b 100644 --- a/precompiles/common/types.go +++ b/precompiles/common/types.go @@ -5,46 +5,17 @@ import ( "math/big" "reflect" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" ) // TrueValue is the byte array representing a true value in solidity. var TrueValue = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1} -// ICS20Allocation defines the spend limit for a particular port and channel. -// We need this to be able to unpack to big.Int instead of math.Int. -type ICS20Allocation struct { - SourcePort string - SourceChannel string - SpendLimit []Coin - AllowList []string - AllowedPacketData []string -} - -// Coin defines a struct that stores all needed information about a coin -// in types native to the EVM. -type Coin struct { - Denom string - Amount *big.Int -} - -// DecCoin defines a struct that stores all needed information about a decimal coin -// in types native to the EVM. -type DecCoin struct { - Denom string - Amount *big.Int - Precision uint8 -} - -// Dec defines a struct that represents a decimal number of a given precision -// in types native to the EVM. -type Dec struct { - Value *big.Int - Precision uint8 -} - // ToSDKType converts the Coin to the Cosmos SDK representation. func (c Coin) ToSDKType() sdk.Coin { return sdk.NewCoin(c.Denom, math.NewIntFromBigInt(c.Amount)) @@ -135,3 +106,44 @@ func NewSdkCoinsFromCoins(coins []Coin) (sdk.Coins, error) { } return sdkCoins.Sort(), nil } + +func (p PageRequest) ToPageRequest() *query.PageRequest { + return &query.PageRequest{ + Key: p.Key, + Offset: p.Offset, + Limit: p.Limit, + CountTotal: p.CountTotal, + Reverse: p.Reverse, + } +} + +func FromPageResponse(pr *query.PageResponse) (p PageResponse) { + if pr != nil { + return + } + + p.NextKey = pr.NextKey + p.Total = pr.Total + return +} + +func FromProofHeight(ch clienttypes.Height) *Height { + var h Height + h.RevisionNumber = ch.RevisionNumber + h.RevisionHeight = ch.RevisionHeight + return &h +} + +func (h Height) ToProofHeight() clienttypes.Height { + return clienttypes.Height{ + RevisionNumber: h.RevisionNumber, + RevisionHeight: h.RevisionHeight, + } +} + +func NewHeight(revisionNumber, revisionHeight uint64) Height { + return Height{ + RevisionNumber: revisionNumber, + RevisionHeight: revisionHeight, + } +} diff --git a/precompiles/types/defaults.go b/precompiles/types/defaults.go index 5d9bbd63a..504d301c9 100644 --- a/precompiles/types/defaults.go +++ b/precompiles/types/defaults.go @@ -4,6 +4,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" evmaddress "github.com/cosmos/evm/encoding/address" ibcutils "github.com/cosmos/evm/ibc" cmn "github.com/cosmos/evm/precompiles/common" @@ -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..3dffdeb74 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 cmn.BankMsgServer, bankKeeper cmn.BankKeeper, erc20Keeper *erc20Keeper.Keeper, ) StaticPrecompiles { - bankPrecompile := bankprecompile.NewPrecompile(bankKeeper, erc20Keeper) + bankPrecompile := bankprecompile.NewPrecompile(bankMsgServer, bankKeeper, erc20Keeper) s[bankPrecompile.Address()] = bankPrecompile return s } From e2968826b1aa3a4219f71c06198114a45b950a93 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 00:50:47 +0800 Subject: [PATCH 02/14] cleanup --- precompiles/bank/bank.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 510e9e9c0..a5221e0fa 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -32,14 +32,14 @@ var ABI = []string{ "function supplyOf(address contract) returns (uint totalSupply)", // v2 design - "function name(string denom) external returns (string name)", + "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 contractor abi + // generate the erc20 constructor abi "function erc20ctor(string denom, address bank)", } From 850ddddd9083673b75b92e165770a7b6dd16cab9 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 00:53:49 +0800 Subject: [PATCH 03/14] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 758cc5462..1f94e177e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,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 From 0527c44567c51ef7148958758d59c0cadaebfa3c Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 01:42:58 +0800 Subject: [PATCH 04/14] keep legacy tests happy --- precompiles/bank/bank.abi.go | 12 +- precompiles/bank/bank.go | 25 +++- precompiles/bank/query.go | 8 +- .../precompiles/bank/test_query.go | 119 +++++------------- .../precompiles/bank/test_utils.go | 11 +- 5 files changed, 70 insertions(+), 105 deletions(-) diff --git a/precompiles/bank/bank.abi.go b/precompiles/bank/bank.abi.go index 0f94eb6e5..d21f16f22 100644 --- a/precompiles/bank/bank.abi.go +++ b/precompiles/bank/bank.abi.go @@ -56,8 +56,8 @@ var _ abi.Tuple = (*Balance)(nil) // Balance represents an ABI tuple type Balance struct { - Contract common.Address - Amount *big.Int + ContractAddress common.Address + Amount *big.Int } // EncodedSize returns the total encoded size of Balance @@ -71,8 +71,8 @@ func (t Balance) EncodedSize() int { func (value Balance) EncodeTo(buf []byte) (int, error) { // Encode tuple fields dynamicOffset := BalanceStaticSize // Start dynamic data after static section - // Field Contract: address - if _, err := abi.EncodeAddress(value.Contract, buf[0:]); err != nil { + // Field ContractAddress: address + if _, err := abi.EncodeAddress(value.ContractAddress, buf[0:]); err != nil { return 0, err } @@ -102,8 +102,8 @@ func (t *Balance) Decode(data []byte) (int, error) { err error ) dynamicOffset := 64 - // Decode static field Contract: address - t.Contract, _, err = abi.DecodeAddress(data[0:]) + // Decode static field ContractAddress: address + t.ContractAddress, _, err = abi.DecodeAddress(data[0:]) if err != nil { return 0, err } diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index a5221e0fa..73da46811 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -6,6 +6,7 @@ package bank import ( + "bytes" "fmt" "github.com/ethereum/go-ethereum/accounts/abi" @@ -22,11 +23,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -//go:generate go run ../cmd -var=ABI -output bank.abi.go +//go:generate go run ../cmd -var=HumanABI -output bank.abi.go -var ABI = []string{ +var HumanABI = []string{ // backwards compatibility - "struct Balance{ address contract; uint amount; }", + "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)", @@ -43,6 +44,22 @@ var ABI = []string{ "function erc20ctor(string denom, address bank)", } +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f []byte + ABI abi.ABI +) + +func init() { + var err error + ABI, err = abi.JSON(bytes.NewReader(f)) + if err != nil { + panic(err) + } +} + const ( // GasBalances defines the gas cost for a single ERC-20 balanceOf query GasBalances = 2_851 @@ -62,6 +79,7 @@ var _ vm.PrecompiledContract = &Precompile{} type Precompile struct { cmn.Precompile + abi.ABI bankMsgServer cmn.BankMsgServer bankKeeper cmn.BankKeeper erc20Keeper cmn.ERC20Keeper @@ -82,6 +100,7 @@ func NewPrecompile( TransientKVGasConfig: storetypes.GasConfig{}, ContractAddress: common.HexToAddress(evmtypes.BankPrecompileAddress), }, + ABI: ABI, bankMsgServer: bankMsgServer, bankKeeper: bankKeeper, erc20Keeper: erc20Keeper, diff --git a/precompiles/bank/query.go b/precompiles/bank/query.go index 932edf8ee..8aae70c67 100644 --- a/precompiles/bank/query.go +++ b/precompiles/bank/query.go @@ -47,8 +47,8 @@ func (p Precompile) Balances( } balances = append(balances, Balance{ - Contract: contractAddress, - Amount: coin.Amount.BigInt(), + ContractAddress: contractAddress, + Amount: coin.Amount.BigInt(), }) return false @@ -84,8 +84,8 @@ func (p Precompile) TotalSupply( } totalSupply = append(totalSupply, Balance{ - Contract: contractAddress, - Amount: coin.Amount.BigInt(), + ContractAddress: contractAddress, + Amount: coin.Amount.BigInt(), }) return false 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(), ) } From 3d2adc158d6570db559f2ebb6c9c4f9d12ff7790 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 02:28:33 +0800 Subject: [PATCH 05/14] fix tests --- precompiles/bank/bank.go | 8 +- precompiles/bank/bank_test.go | 346 +++++ precompiles/bank/erc20/abi.go | 1198 ++++++++++++++++++ precompiles/bank/interfaces.go | 21 + precompiles/bank/mock.go | 161 +++ precompiles/common/interfaces.go | 5 - precompiles/types/static_precompiles.go | 4 +- x/vm/statedb/{mock_test.go => mockkeeper.go} | 15 +- 8 files changed, 1739 insertions(+), 19 deletions(-) create mode 100644 precompiles/bank/bank_test.go create mode 100644 precompiles/bank/erc20/abi.go create mode 100644 precompiles/bank/interfaces.go create mode 100644 precompiles/bank/mock.go rename x/vm/statedb/{mock_test.go => mockkeeper.go} (90%) diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 73da46811..57981357e 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -80,16 +80,16 @@ type Precompile struct { cmn.Precompile abi.ABI - bankMsgServer cmn.BankMsgServer - bankKeeper cmn.BankKeeper + bankMsgServer BankMsgServer + bankKeeper BankKeeper erc20Keeper cmn.ERC20Keeper } // NewPrecompile creates a new bank Precompile instance implementing the // PrecompiledContract interface. func NewPrecompile( - bankMsgServer cmn.BankMsgServer, - bankKeeper cmn.BankKeeper, + bankMsgServer BankMsgServer, + bankKeeper BankKeeper, erc20Keeper cmn.ERC20Keeper, ) *Precompile { // NOTE: we set an empty gas configuration to avoid extra gas costs diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go new file mode 100644 index 000000000..15c687f01 --- /dev/null +++ b/precompiles/bank/bank_test.go @@ -0,0 +1,346 @@ +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/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() + 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/abi.go b/precompiles/bank/erc20/abi.go new file mode 100644 index 000000000..26ce340a8 --- /dev/null +++ b/precompiles/bank/erc20/abi.go @@ -0,0 +1,1198 @@ +// Code generated by go-abi. DO NOT EDIT. + +package erc20 + +import ( + "encoding/binary" + "errors" + "fmt" + "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 + ) + dynamicOffset := 32 + // Decode dynamic field Name + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Name") + } + 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 + ) + dynamicOffset := 32 + // Decode dynamic field Symbol + { + offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + if offset != dynamicOffset { + return 0, errors.New("invalid offset for dynamic field Symbol") + } + 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 fmt.Errorf("invalid number of topics for Approval event: expected 3, got %d", len(topics)) + } + if topics[0] != ApprovalEventTopic { + return fmt.Errorf("invalid event topic for Approval event") + } + 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 fmt.Errorf("invalid number of topics for Transfer event: expected 3, got %d", len(topics)) + } + if topics[0] != TransferEventTopic { + return fmt.Errorf("invalid event topic for Transfer event") + } + 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/interfaces.go b/precompiles/bank/interfaces.go new file mode 100644 index 000000000..f06ee3dd1 --- /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 BankMsgServer interface { + // Send defines a method for sending coins from one account to another account. + Send(context.Context, *banktypes.MsgSend) (*banktypes.MsgSendResponse, error) +} + +type BankKeeper 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..60967510b --- /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 ( + _ BankKeeper = MockBankKeeper{} + _ BankMsgServer = 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/common/interfaces.go b/precompiles/common/interfaces.go index c613b75c1..e69e11d39 100644 --- a/precompiles/common/interfaces.go +++ b/precompiles/common/interfaces.go @@ -28,11 +28,6 @@ type BankKeeper interface { BlockedAddr(addr sdk.AccAddress) bool } -type BankMsgServer interface { - // Send defines a method for sending coins from one account to another account. - Send(context.Context, *banktypes.MsgSend) (*banktypes.MsgSendResponse, error) -} - type TransferKeeper interface { Denom(ctx context.Context, req *ibctypes.QueryDenomRequest) (*ibctypes.QueryDenomResponse, error) Denoms(ctx context.Context, req *ibctypes.QueryDenomsRequest) (*ibctypes.QueryDenomsResponse, error) diff --git a/precompiles/types/static_precompiles.go b/precompiles/types/static_precompiles.go index 3dffdeb74..33edc9dd8 100644 --- a/precompiles/types/static_precompiles.go +++ b/precompiles/types/static_precompiles.go @@ -132,11 +132,11 @@ func (s StaticPrecompiles) WithICS20Precompile( } func (s StaticPrecompiles) WithBankPrecompile( - bankMsgServer cmn.BankMsgServer, + bankMsgServer bankprecompile.BankMsgServer, bankKeeper cmn.BankKeeper, erc20Keeper *erc20Keeper.Keeper, ) StaticPrecompiles { - bankPrecompile := bankprecompile.NewPrecompile(bankMsgServer, bankKeeper, erc20Keeper) + bankPrecompile := bankprecompile.NewPrecompile(bankMsgServer, bankprecompile.BankKeeper(bankKeeper), erc20Keeper) s[bankPrecompile.Address()] = bankPrecompile return s } 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 } From 062b2a0bc5111cbd1cc7e60b790b7d3b654e4a43 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 02:32:08 +0800 Subject: [PATCH 06/14] fix lint --- precompiles/bank/bank.go | 9 ++++----- precompiles/bank/bank_test.go | 4 +++- precompiles/bank/erc20.go | 4 ++-- precompiles/bank/interfaces.go | 4 ++-- precompiles/bank/mock.go | 4 ++-- precompiles/bank/tx.go | 4 +++- precompiles/types/defaults.go | 2 +- precompiles/types/static_precompiles.go | 4 ++-- rpc/namespaces/ethereum/debug/trace_fallback.go | 1 - server/config/opendb.go | 1 - server/config/opendb_rocksdb.go | 5 +++-- x/vm/types/config.go | 1 - x/vm/types/config_testing.go | 1 - x/vm/types/denom_config.go | 1 - x/vm/types/denom_config_testing.go | 1 - 15 files changed, 22 insertions(+), 24 deletions(-) diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 57981357e..650e86d9e 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -80,16 +80,16 @@ type Precompile struct { cmn.Precompile abi.ABI - bankMsgServer BankMsgServer - bankKeeper BankKeeper + bankMsgServer MsgServer + bankKeeper Keeper erc20Keeper cmn.ERC20Keeper } // NewPrecompile creates a new bank Precompile instance implementing the // PrecompiledContract interface. func NewPrecompile( - bankMsgServer BankMsgServer, - bankKeeper BankKeeper, + bankMsgServer MsgServer, + bankKeeper Keeper, erc20Keeper cmn.ERC20Keeper, ) *Precompile { // NOTE: we set an empty gas configuration to avoid extra gas costs @@ -166,7 +166,6 @@ func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Co default: return nil, fmt.Errorf(cmn.ErrUnknownMethodID, methodID) } - } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index 15c687f01..08581770f 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -162,7 +162,8 @@ func TestBankPrecompile(t *testing.T) { {"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), + { + "supplyOf", user1, NewTotalSupply0Call(token.Denom), &TotalSupply0Return{new(big.Int).SetUint64(amount)}, nil, }, @@ -213,6 +214,7 @@ func TestBankPrecompile(t *testing.T) { 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) diff --git a/precompiles/bank/erc20.go b/precompiles/bank/erc20.go index e144dcbfc..6ba0636ae 100644 --- a/precompiles/bank/erc20.go +++ b/precompiles/bank/erc20.go @@ -1,10 +1,10 @@ package bank import ( - _ "embed" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + + _ "embed" ) // generated with solc 0.8.30+commit.73712a01: diff --git a/precompiles/bank/interfaces.go b/precompiles/bank/interfaces.go index f06ee3dd1..1c7de2f9e 100644 --- a/precompiles/bank/interfaces.go +++ b/precompiles/bank/interfaces.go @@ -7,12 +7,12 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -type BankMsgServer interface { +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 BankKeeper interface { +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 diff --git a/precompiles/bank/mock.go b/precompiles/bank/mock.go index 60967510b..8ce279c86 100644 --- a/precompiles/bank/mock.go +++ b/precompiles/bank/mock.go @@ -31,8 +31,8 @@ type MockBankMsgServer struct { } var ( - _ BankKeeper = MockBankKeeper{} - _ BankMsgServer = MockBankMsgServer{} + _ Keeper = MockBankKeeper{} + _ MsgServer = MockBankMsgServer{} ) func NewMockBankKeeper() MockBankKeeper { diff --git a/precompiles/bank/tx.go b/precompiles/bank/tx.go index 87b3b8ad2..a097ba28b 100644 --- a/precompiles/bank/tx.go +++ b/precompiles/bank/tx.go @@ -6,10 +6,12 @@ import ( "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" - evmtypes "github.com/cosmos/evm/x/vm/types" ) func (p Precompile) TransferFrom( diff --git a/precompiles/types/defaults.go b/precompiles/types/defaults.go index 504d301c9..824d11a23 100644 --- a/precompiles/types/defaults.go +++ b/precompiles/types/defaults.go @@ -4,7 +4,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" evmaddress "github.com/cosmos/evm/encoding/address" ibcutils "github.com/cosmos/evm/ibc" cmn "github.com/cosmos/evm/precompiles/common" @@ -16,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" diff --git a/precompiles/types/static_precompiles.go b/precompiles/types/static_precompiles.go index 33edc9dd8..93a667165 100644 --- a/precompiles/types/static_precompiles.go +++ b/precompiles/types/static_precompiles.go @@ -132,11 +132,11 @@ func (s StaticPrecompiles) WithICS20Precompile( } func (s StaticPrecompiles) WithBankPrecompile( - bankMsgServer bankprecompile.BankMsgServer, + bankMsgServer bankprecompile.MsgServer, bankKeeper cmn.BankKeeper, erc20Keeper *erc20Keeper.Keeper, ) StaticPrecompiles { - bankPrecompile := bankprecompile.NewPrecompile(bankMsgServer, bankprecompile.BankKeeper(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/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 ca731fc3a..8fb090edc 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 fede6ffdb..233f9a1e7 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 From 091b21120164ab6a23c21e50aa3bfa9919105785 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 15:52:14 +0800 Subject: [PATCH 07/14] remove unused file --- precompiles/bank/types.go | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 precompiles/bank/types.go diff --git a/precompiles/bank/types.go b/precompiles/bank/types.go deleted file mode 100644 index 6b8e189bb..000000000 --- a/precompiles/bank/types.go +++ /dev/null @@ -1,39 +0,0 @@ -package bank - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - - cmn "github.com/cosmos/evm/precompiles/common" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// 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 -} From dadb60b39944b2507a38986ebf94f3d14bb263d7 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 6 Nov 2025 15:54:33 +0800 Subject: [PATCH 08/14] cleanup unused files --- precompiles/common/abi.go | 16 - precompiles/common/common.abi.go | 1009 ------------------------------ precompiles/common/types.go | 76 +-- 3 files changed, 32 insertions(+), 1069 deletions(-) delete mode 100644 precompiles/common/common.abi.go diff --git a/precompiles/common/abi.go b/precompiles/common/abi.go index d62b6a79b..e451f93d7 100644 --- a/precompiles/common/abi.go +++ b/precompiles/common/abi.go @@ -12,22 +12,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -//go:generate go run github.com/yihuang/go-abi/cmd -var=CommonABI -output common.abi.go - -var CommonABI = []string{ - "struct Coin {string denom; uint256 amount;}", - "struct DecCoin {string denom; uint256 amount; uint8 precision;}", - "struct Dec {uint256 value; uint8 precision;}", - "struct Height { uint64 revisionNumber; uint64 revisionHeight; }", - "struct PageRequest { bytes key; uint64 offset; uint64 limit; bool countTotal; bool reverse; }", - "struct PageResponse { bytes nextKey; uint64 total; }", - "struct ICS20Allocation { string sourcePort; string sourceChannel; Coin[] spendLimit; string[] allowList; string[] allowedPacketData; }", - - // there's no dedicated tyeps for structs in ABI, - // the dummy function to keep them in the ABI - "function dummy(Coin a, DecCoin b, Dec c, Height d, PageRequest e, PageResponse f, ICS20Allocation g)", -} - // MakeTopic converts a filter query argument into a filter topic. // NOTE: This was copied from accounts/abi/topics.go func MakeTopic(rule interface{}) (common.Hash, error) { diff --git a/precompiles/common/common.abi.go b/precompiles/common/common.abi.go deleted file mode 100644 index eebfe6500..000000000 --- a/precompiles/common/common.abi.go +++ /dev/null @@ -1,1009 +0,0 @@ -// Code generated by go-abi. DO NOT EDIT. - -package common - -import ( - "encoding/binary" - "errors" - "fmt" - "io" - "math/big" - - "github.com/yihuang/go-abi" -) - -// Function selectors -var ( - // dummy((string,uint256),(string,uint256,uint8),(uint256,uint8),(uint64,uint64),(bytes,uint64,uint64,bool,bool),(bytes,uint64),(string,string,(string,uint256)[],string[],string[])) - DummySelector = [4]byte{0x59, 0xd4, 0xfe, 0x1a} -) - -// Big endian integer versions of function selectors -const ( - DummyID = 1507130906 -) - -const CoinStaticSize = 64 - -var _ abi.Tuple = (*Coin)(nil) - -// Coin represents an ABI tuple -type Coin struct { - Denom string - Amount *big.Int -} - -// EncodedSize returns the total encoded size of Coin -func (t Coin) EncodedSize() int { - dynamicSize := 0 - dynamicSize += abi.SizeString(t.Denom) - - return CoinStaticSize + dynamicSize -} - -// EncodeTo encodes Coin to ABI bytes in the provided buffer -func (value Coin) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := CoinStaticSize // 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 Amount: uint256 - if _, err := abi.EncodeUint256(value.Amount, buf[32:]); err != nil { - return 0, err - } - - return dynamicOffset, nil -} - -// Encode encodes Coin to ABI bytes -func (value Coin) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes Coin from ABI bytes in the provided buffer -func (t *Coin) Decode(data []byte) (int, error) { - if len(data) < 64 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - n int - ) - dynamicOffset := 64 - // Decode dynamic field Denom - { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") - } - t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode static field Amount: uint256 - t.Amount, _, err = abi.DecodeUint256(data[32:]) - if err != nil { - return 0, err - } - return dynamicOffset, nil -} - -const DecStaticSize = 64 - -var _ abi.Tuple = (*Dec)(nil) - -// Dec represents an ABI tuple -type Dec struct { - Value *big.Int - Precision uint8 -} - -// EncodedSize returns the total encoded size of Dec -func (t Dec) EncodedSize() int { - dynamicSize := 0 - - return DecStaticSize + dynamicSize -} - -// EncodeTo encodes Dec to ABI bytes in the provided buffer -func (value Dec) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := DecStaticSize // Start dynamic data after static section - // Field Value: uint256 - if _, err := abi.EncodeUint256(value.Value, buf[0:]); err != nil { - return 0, err - } - - // Field Precision: uint8 - if _, err := abi.EncodeUint8(value.Precision, buf[32:]); err != nil { - return 0, err - } - - return dynamicOffset, nil -} - -// Encode encodes Dec to ABI bytes -func (value Dec) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes Dec from ABI bytes in the provided buffer -func (t *Dec) Decode(data []byte) (int, error) { - if len(data) < 64 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - ) - dynamicOffset := 64 - // Decode static field Value: uint256 - t.Value, _, err = abi.DecodeUint256(data[0:]) - if err != nil { - return 0, err - } - // Decode static field Precision: uint8 - t.Precision, _, err = abi.DecodeUint8(data[32:]) - if err != nil { - return 0, err - } - return dynamicOffset, nil -} - -const DecCoinStaticSize = 96 - -var _ abi.Tuple = (*DecCoin)(nil) - -// DecCoin represents an ABI tuple -type DecCoin struct { - Denom string - Amount *big.Int - Precision uint8 -} - -// EncodedSize returns the total encoded size of DecCoin -func (t DecCoin) EncodedSize() int { - dynamicSize := 0 - dynamicSize += abi.SizeString(t.Denom) - - return DecCoinStaticSize + dynamicSize -} - -// EncodeTo encodes DecCoin to ABI bytes in the provided buffer -func (value DecCoin) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := DecCoinStaticSize // 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 Amount: uint256 - if _, err := abi.EncodeUint256(value.Amount, buf[32:]); err != nil { - return 0, err - } - - // Field Precision: uint8 - if _, err := abi.EncodeUint8(value.Precision, buf[64:]); err != nil { - return 0, err - } - - return dynamicOffset, nil -} - -// Encode encodes DecCoin to ABI bytes -func (value DecCoin) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes DecCoin from ABI bytes in the provided buffer -func (t *DecCoin) Decode(data []byte) (int, error) { - if len(data) < 96 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - n int - ) - dynamicOffset := 96 - // Decode dynamic field Denom - { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") - } - t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode static field Amount: uint256 - t.Amount, _, err = abi.DecodeUint256(data[32:]) - if err != nil { - return 0, err - } - // Decode static field Precision: uint8 - t.Precision, _, err = abi.DecodeUint8(data[64:]) - if err != nil { - return 0, err - } - return dynamicOffset, nil -} - -const HeightStaticSize = 64 - -var _ abi.Tuple = (*Height)(nil) - -// Height represents an ABI tuple -type Height struct { - RevisionNumber uint64 - RevisionHeight uint64 -} - -// EncodedSize returns the total encoded size of Height -func (t Height) EncodedSize() int { - dynamicSize := 0 - - return HeightStaticSize + dynamicSize -} - -// EncodeTo encodes Height to ABI bytes in the provided buffer -func (value Height) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := HeightStaticSize // Start dynamic data after static section - // Field RevisionNumber: uint64 - if _, err := abi.EncodeUint64(value.RevisionNumber, buf[0:]); err != nil { - return 0, err - } - - // Field RevisionHeight: uint64 - if _, err := abi.EncodeUint64(value.RevisionHeight, buf[32:]); err != nil { - return 0, err - } - - return dynamicOffset, nil -} - -// Encode encodes Height to ABI bytes -func (value Height) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes Height from ABI bytes in the provided buffer -func (t *Height) Decode(data []byte) (int, error) { - if len(data) < 64 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - ) - dynamicOffset := 64 - // Decode static field RevisionNumber: uint64 - t.RevisionNumber, _, err = abi.DecodeUint64(data[0:]) - if err != nil { - return 0, err - } - // Decode static field RevisionHeight: uint64 - t.RevisionHeight, _, err = abi.DecodeUint64(data[32:]) - if err != nil { - return 0, err - } - return dynamicOffset, nil -} - -const ICS20AllocationStaticSize = 160 - -var _ abi.Tuple = (*ICS20Allocation)(nil) - -// ICS20Allocation represents an ABI tuple -type ICS20Allocation struct { - SourcePort string - SourceChannel string - SpendLimit []Coin - AllowList []string - AllowedPacketData []string -} - -// EncodedSize returns the total encoded size of ICS20Allocation -func (t ICS20Allocation) EncodedSize() int { - dynamicSize := 0 - dynamicSize += abi.SizeString(t.SourcePort) - dynamicSize += abi.SizeString(t.SourceChannel) - dynamicSize += SizeCoinSlice(t.SpendLimit) - dynamicSize += abi.SizeStringSlice(t.AllowList) - dynamicSize += abi.SizeStringSlice(t.AllowedPacketData) - - return ICS20AllocationStaticSize + dynamicSize -} - -// EncodeTo encodes ICS20Allocation to ABI bytes in the provided buffer -func (value ICS20Allocation) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := ICS20AllocationStaticSize // Start dynamic data after static section - var ( - err error - n int - ) - // Field SourcePort: string - // Encode offset pointer - binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = abi.EncodeString(value.SourcePort, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field SourceChannel: string - // Encode offset pointer - binary.BigEndian.PutUint64(buf[32+24:32+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = abi.EncodeString(value.SourceChannel, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field SpendLimit: (string,uint256)[] - // Encode offset pointer - binary.BigEndian.PutUint64(buf[64+24:64+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = EncodeCoinSlice(value.SpendLimit, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field AllowList: string[] - // Encode offset pointer - binary.BigEndian.PutUint64(buf[96+24:96+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = abi.EncodeStringSlice(value.AllowList, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field AllowedPacketData: string[] - // Encode offset pointer - binary.BigEndian.PutUint64(buf[128+24:128+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = abi.EncodeStringSlice(value.AllowedPacketData, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - return dynamicOffset, nil -} - -// Encode encodes ICS20Allocation to ABI bytes -func (value ICS20Allocation) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes ICS20Allocation from ABI bytes in the provided buffer -func (t *ICS20Allocation) Decode(data []byte) (int, error) { - if len(data) < 160 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - n int - ) - dynamicOffset := 160 - // Decode dynamic field SourcePort - { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field SourcePort") - } - t.SourcePort, n, err = abi.DecodeString(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field SourceChannel - { - offset := int(binary.BigEndian.Uint64(data[32+24 : 32+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field SourceChannel") - } - t.SourceChannel, n, err = abi.DecodeString(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field SpendLimit - { - offset := int(binary.BigEndian.Uint64(data[64+24 : 64+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field SpendLimit") - } - t.SpendLimit, n, err = DecodeCoinSlice(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field AllowList - { - offset := int(binary.BigEndian.Uint64(data[96+24 : 96+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field AllowList") - } - t.AllowList, n, err = abi.DecodeStringSlice(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field AllowedPacketData - { - offset := int(binary.BigEndian.Uint64(data[128+24 : 128+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field AllowedPacketData") - } - t.AllowedPacketData, n, err = abi.DecodeStringSlice(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - return dynamicOffset, nil -} - -const PageRequestStaticSize = 160 - -var _ abi.Tuple = (*PageRequest)(nil) - -// PageRequest represents an ABI tuple -type PageRequest struct { - Key []byte - Offset uint64 - Limit uint64 - CountTotal bool - Reverse bool -} - -// EncodedSize returns the total encoded size of PageRequest -func (t PageRequest) EncodedSize() int { - dynamicSize := 0 - dynamicSize += abi.SizeBytes(t.Key) - - return PageRequestStaticSize + dynamicSize -} - -// EncodeTo encodes PageRequest to ABI bytes in the provided buffer -func (value PageRequest) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := PageRequestStaticSize // Start dynamic data after static section - var ( - err error - n int - ) - // Field Key: bytes - // Encode offset pointer - binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = abi.EncodeBytes(value.Key, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field Offset: uint64 - if _, err := abi.EncodeUint64(value.Offset, buf[32:]); err != nil { - return 0, err - } - - // Field Limit: uint64 - if _, err := abi.EncodeUint64(value.Limit, buf[64:]); err != nil { - return 0, err - } - - // Field CountTotal: bool - if _, err := abi.EncodeBool(value.CountTotal, buf[96:]); err != nil { - return 0, err - } - - // Field Reverse: bool - if _, err := abi.EncodeBool(value.Reverse, buf[128:]); err != nil { - return 0, err - } - - return dynamicOffset, nil -} - -// Encode encodes PageRequest to ABI bytes -func (value PageRequest) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes PageRequest from ABI bytes in the provided buffer -func (t *PageRequest) Decode(data []byte) (int, error) { - if len(data) < 160 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - n int - ) - dynamicOffset := 160 - // Decode dynamic field Key - { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Key") - } - t.Key, n, err = abi.DecodeBytes(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode static field Offset: uint64 - t.Offset, _, err = abi.DecodeUint64(data[32:]) - if err != nil { - return 0, err - } - // Decode static field Limit: uint64 - t.Limit, _, err = abi.DecodeUint64(data[64:]) - if err != nil { - return 0, err - } - // Decode static field CountTotal: bool - t.CountTotal, _, err = abi.DecodeBool(data[96:]) - if err != nil { - return 0, err - } - // Decode static field Reverse: bool - t.Reverse, _, err = abi.DecodeBool(data[128:]) - if err != nil { - return 0, err - } - return dynamicOffset, nil -} - -const PageResponseStaticSize = 64 - -var _ abi.Tuple = (*PageResponse)(nil) - -// PageResponse represents an ABI tuple -type PageResponse struct { - NextKey []byte - Total uint64 -} - -// EncodedSize returns the total encoded size of PageResponse -func (t PageResponse) EncodedSize() int { - dynamicSize := 0 - dynamicSize += abi.SizeBytes(t.NextKey) - - return PageResponseStaticSize + dynamicSize -} - -// EncodeTo encodes PageResponse to ABI bytes in the provided buffer -func (value PageResponse) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := PageResponseStaticSize // Start dynamic data after static section - var ( - err error - n int - ) - // Field NextKey: bytes - // Encode offset pointer - binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = abi.EncodeBytes(value.NextKey, buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field Total: uint64 - if _, err := abi.EncodeUint64(value.Total, buf[32:]); err != nil { - return 0, err - } - - return dynamicOffset, nil -} - -// Encode encodes PageResponse to ABI bytes -func (value PageResponse) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes PageResponse from ABI bytes in the provided buffer -func (t *PageResponse) Decode(data []byte) (int, error) { - if len(data) < 64 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - n int - ) - dynamicOffset := 64 - // Decode dynamic field NextKey - { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field NextKey") - } - t.NextKey, n, err = abi.DecodeBytes(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode static field Total: uint64 - t.Total, _, err = abi.DecodeUint64(data[32:]) - if err != nil { - return 0, err - } - return dynamicOffset, nil -} - -// EncodeCoinSlice encodes (string,uint256)[] to ABI bytes -func EncodeCoinSlice(value []Coin, buf []byte) (int, error) { - // Encode length - binary.BigEndian.PutUint64(buf[24:32], uint64(len(value))) - buf = buf[32:] - - // Encode elements with dynamic types - var offset int - dynamicOffset := len(value) * 32 - for _, elem := range value { - // Write offset for element - offset += 32 - binary.BigEndian.PutUint64(buf[offset-8:offset], uint64(dynamicOffset)) - - // Write element at dynamic region - n, err := elem.EncodeTo(buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - - return dynamicOffset + 32, nil -} - -// SizeCoinSlice returns the encoded size of (string,uint256)[] -func SizeCoinSlice(value []Coin) int { - size := 32 + 32*len(value) // length + offset pointers for dynamic elements - for _, elem := range value { - size += elem.EncodedSize() - } - return size -} - -// DecodeCoinSlice decodes (string,uint256)[] from ABI bytes -func DecodeCoinSlice(data []byte) ([]Coin, int, error) { - // Decode length - length := int(binary.BigEndian.Uint64(data[24:32])) - if len(data) < 32 { - return nil, 0, io.ErrUnexpectedEOF - } - data = data[32:] - if len(data) < 32*length { - return nil, 0, io.ErrUnexpectedEOF - } - var ( - n int - err error - offset int - ) - // Decode elements with dynamic types - result := make([]Coin, length) - dynamicOffset := length * 32 - for i := 0; i < length; i++ { - offset += 32 - tmp := int(binary.BigEndian.Uint64(data[offset-8 : offset])) - if dynamicOffset != tmp { - return nil, 0, fmt.Errorf("invalid offset for slice element %d: expected %d, got %d", i, dynamicOffset, tmp) - } - n, err = result[i].Decode(data[dynamicOffset:]) - if err != nil { - return nil, 0, err - } - dynamicOffset += n - } - return result, dynamicOffset + 32, nil -} - -var _ abi.Method = (*DummyCall)(nil) - -const DummyCallStaticSize = 288 - -var _ abi.Tuple = (*DummyCall)(nil) - -// DummyCall represents an ABI tuple -type DummyCall struct { - A Coin - B DecCoin - C Dec - D Height - E PageRequest - F PageResponse - G ICS20Allocation -} - -// EncodedSize returns the total encoded size of DummyCall -func (t DummyCall) EncodedSize() int { - dynamicSize := 0 - dynamicSize += t.A.EncodedSize() - dynamicSize += t.B.EncodedSize() - dynamicSize += t.E.EncodedSize() - dynamicSize += t.F.EncodedSize() - dynamicSize += t.G.EncodedSize() - - return DummyCallStaticSize + dynamicSize -} - -// EncodeTo encodes DummyCall to ABI bytes in the provided buffer -func (value DummyCall) EncodeTo(buf []byte) (int, error) { - // Encode tuple fields - dynamicOffset := DummyCallStaticSize // Start dynamic data after static section - var ( - err error - n int - ) - // Field A: (string,uint256) - // Encode offset pointer - binary.BigEndian.PutUint64(buf[0+24:0+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = value.A.EncodeTo(buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field B: (string,uint256,uint8) - // Encode offset pointer - binary.BigEndian.PutUint64(buf[32+24:32+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = value.B.EncodeTo(buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field C: (uint256,uint8) - if _, err := value.C.EncodeTo(buf[64:]); err != nil { - return 0, err - } - - // Field D: (uint64,uint64) - if _, err := value.D.EncodeTo(buf[128:]); err != nil { - return 0, err - } - - // Field E: (bytes,uint64,uint64,bool,bool) - // Encode offset pointer - binary.BigEndian.PutUint64(buf[192+24:192+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = value.E.EncodeTo(buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field F: (bytes,uint64) - // Encode offset pointer - binary.BigEndian.PutUint64(buf[224+24:224+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = value.F.EncodeTo(buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - // Field G: (string,string,(string,uint256)[],string[],string[]) - // Encode offset pointer - binary.BigEndian.PutUint64(buf[256+24:256+32], uint64(dynamicOffset)) - // Encode dynamic data - n, err = value.G.EncodeTo(buf[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - - return dynamicOffset, nil -} - -// Encode encodes DummyCall to ABI bytes -func (value DummyCall) Encode() ([]byte, error) { - buf := make([]byte, value.EncodedSize()) - if _, err := value.EncodeTo(buf); err != nil { - return nil, err - } - return buf, nil -} - -// Decode decodes DummyCall from ABI bytes in the provided buffer -func (t *DummyCall) Decode(data []byte) (int, error) { - if len(data) < 288 { - return 0, io.ErrUnexpectedEOF - } - var ( - err error - n int - ) - dynamicOffset := 288 - // Decode dynamic field A - { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field A") - } - n, err = t.A.Decode(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field B - { - offset := int(binary.BigEndian.Uint64(data[32+24 : 32+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field B") - } - n, err = t.B.Decode(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode static field C: (uint256,uint8) - _, err = t.C.Decode(data[64:]) - if err != nil { - return 0, err - } - // Decode static field D: (uint64,uint64) - _, err = t.D.Decode(data[128:]) - if err != nil { - return 0, err - } - // Decode dynamic field E - { - offset := int(binary.BigEndian.Uint64(data[192+24 : 192+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field E") - } - n, err = t.E.Decode(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field F - { - offset := int(binary.BigEndian.Uint64(data[224+24 : 224+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field F") - } - n, err = t.F.Decode(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - // Decode dynamic field G - { - offset := int(binary.BigEndian.Uint64(data[256+24 : 256+32])) - if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field G") - } - n, err = t.G.Decode(data[dynamicOffset:]) - if err != nil { - return 0, err - } - dynamicOffset += n - } - return dynamicOffset, nil -} - -// GetMethodName returns the function name -func (t DummyCall) GetMethodName() string { - return "dummy" -} - -// GetMethodID returns the function id -func (t DummyCall) GetMethodID() uint32 { - return DummyID -} - -// GetMethodSelector returns the function selector -func (t DummyCall) GetMethodSelector() [4]byte { - return DummySelector -} - -// EncodeWithSelector encodes dummy arguments to ABI bytes including function selector -func (t DummyCall) EncodeWithSelector() ([]byte, error) { - result := make([]byte, 4+t.EncodedSize()) - copy(result[:4], DummySelector[:]) - if _, err := t.EncodeTo(result[4:]); err != nil { - return nil, err - } - return result, nil -} - -// NewDummyCall constructs a new DummyCall -func NewDummyCall( - a Coin, - b DecCoin, - c Dec, - d Height, - e PageRequest, - f PageResponse, - g ICS20Allocation, -) *DummyCall { - return &DummyCall{ - A: a, - B: b, - C: c, - D: d, - E: e, - F: f, - G: g, - } -} - -// DummyReturn represents the output arguments for dummy function -type DummyReturn struct { - abi.EmptyTuple -} diff --git a/precompiles/common/types.go b/precompiles/common/types.go index 5d8b97f7b..4e1d568b9 100644 --- a/precompiles/common/types.go +++ b/precompiles/common/types.go @@ -5,17 +5,46 @@ import ( "math/big" "reflect" - clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" - "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" ) // TrueValue is the byte array representing a true value in solidity. var TrueValue = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1} +// ICS20Allocation defines the spend limit for a particular port and channel. +// We need this to be able to unpack to big.Int instead of math.Int. +type ICS20Allocation struct { + SourcePort string + SourceChannel string + SpendLimit []Coin + AllowList []string + AllowedPacketData []string +} + +// Coin defines a struct that stores all needed information about a coin +// in types native to the EVM. +type Coin struct { + Denom string + Amount *big.Int +} + +// DecCoin defines a struct that stores all needed information about a decimal coin +// in types native to the EVM. +type DecCoin struct { + Denom string + Amount *big.Int + Precision uint8 +} + +// Dec defines a struct that represents a decimal number of a given precision +// in types native to the EVM. +type Dec struct { + Value *big.Int + Precision uint8 +} + // ToSDKType converts the Coin to the Cosmos SDK representation. func (c Coin) ToSDKType() sdk.Coin { return sdk.NewCoin(c.Denom, math.NewIntFromBigInt(c.Amount)) @@ -106,44 +135,3 @@ func NewSdkCoinsFromCoins(coins []Coin) (sdk.Coins, error) { } return sdkCoins.Sort(), nil } - -func (p PageRequest) ToPageRequest() *query.PageRequest { - return &query.PageRequest{ - Key: p.Key, - Offset: p.Offset, - Limit: p.Limit, - CountTotal: p.CountTotal, - Reverse: p.Reverse, - } -} - -func FromPageResponse(pr *query.PageResponse) (p PageResponse) { - if pr != nil { - return - } - - p.NextKey = pr.NextKey - p.Total = pr.Total - return -} - -func FromProofHeight(ch clienttypes.Height) *Height { - var h Height - h.RevisionNumber = ch.RevisionNumber - h.RevisionHeight = ch.RevisionHeight - return &h -} - -func (h Height) ToProofHeight() clienttypes.Height { - return clienttypes.Height{ - RevisionNumber: h.RevisionNumber, - RevisionHeight: h.RevisionHeight, - } -} - -func NewHeight(revisionNumber, revisionHeight uint64) Height { - return Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } -} From 400831ae47f012046efc703e1fa7d4608d5803e2 Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 14 Nov 2025 17:19:24 +0800 Subject: [PATCH 09/14] go-abi 0.1.0 --- evmd/go.mod | 2 +- evmd/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- precompiles/bank/bank.abi.go | 141 ++++++++++++++++++++++------------ precompiles/bank/erc20/abi.go | 34 ++++---- 6 files changed, 119 insertions(+), 68 deletions(-) diff --git a/evmd/go.mod b/evmd/go.mod index 6a4ebcb79..d6a5aa27d 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -241,7 +241,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.0.0-20251105152715-7472843b6ae6 // indirect + github.com/yihuang/go-abi v0.1.0 // 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 0cae54ad4..4b0bcde93 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -1004,8 +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.0.0-20251105152715-7472843b6ae6 h1:WPjvbj0+yTLpc2PQSxhZuRh9P4prPUQHS7Ap43EO3Zk= -github.com/yihuang/go-abi v0.0.0-20251105152715-7472843b6ae6/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= +github.com/yihuang/go-abi v0.1.0 h1:T618RtH5cdpfUUPAoc/581R0Hw3zPDBL8lXELINAn8A= +github.com/yihuang/go-abi v0.1.0/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 9ccdefc7f..205e9fe0d 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +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.0.0-20251105152715-7472843b6ae6 + github.com/yihuang/go-abi v0.1.0 github.com/zondax/hid v0.9.2 go.uber.org/mock v0.6.0 golang.org/x/crypto v0.43.0 diff --git a/go.sum b/go.sum index 1e706a315..f8137e456 100644 --- a/go.sum +++ b/go.sum @@ -984,8 +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.0.0-20251105152715-7472843b6ae6 h1:WPjvbj0+yTLpc2PQSxhZuRh9P4prPUQHS7Ap43EO3Zk= -github.com/yihuang/go-abi v0.0.0-20251105152715-7472843b6ae6/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= +github.com/yihuang/go-abi v0.1.0 h1:T618RtH5cdpfUUPAoc/581R0Hw3zPDBL8lXELINAn8A= +github.com/yihuang/go-abi v0.1.0/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/precompiles/bank/bank.abi.go b/precompiles/bank/bank.abi.go index d21f16f22..7bcf81b09 100644 --- a/precompiles/bank/bank.abi.go +++ b/precompiles/bank/bank.abi.go @@ -4,7 +4,6 @@ package bank import ( "encoding/binary" - "errors" "io" "math/big" @@ -143,17 +142,19 @@ func SizeBalanceSlice(value []Balance) int { // DecodeBalanceSlice decodes (address,uint256)[] from ABI bytes func DecodeBalanceSlice(data []byte) ([]Balance, int, error) { // Decode length - length := int(binary.BigEndian.Uint64(data[24:32])) 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 len(data) < 64*length { + if length > len(data) || length*64 > len(data) { return nil, 0, io.ErrUnexpectedEOF } var ( n int - err error offset int ) // Decode elements with static types @@ -229,8 +230,9 @@ func (t *BalanceOfCall) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 64 // Decode static field Account: address @@ -240,9 +242,12 @@ func (t *BalanceOfCall) Decode(data []byte) (int, error) { } // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[32+24 : 32+32])) + offset, err = abi.DecodeSize(data[32:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -486,15 +491,19 @@ func (t *BalancesReturn) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Balances { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Balances") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Balances, n, err = DecodeBalanceSlice(data[dynamicOffset:]) if err != nil { @@ -560,15 +569,19 @@ func (t *DecimalsCall) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -728,15 +741,19 @@ func (t *Erc20ctorCall) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 64 // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -848,15 +865,19 @@ func (t *NameCall) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -954,15 +975,19 @@ func (t *NameReturn) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Name { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Name") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Name, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -1172,15 +1197,19 @@ func (t *SymbolCall) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -1278,15 +1307,19 @@ func (t *SymbolReturn) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Symbol { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Symbol") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Symbol, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -1387,15 +1420,19 @@ func (t *TotalSupplyReturn) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field TotalSupply { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field TotalSupply") + return 0, abi.ErrInvalidOffsetForDynamicField } t.TotalSupply, n, err = DecodeBalanceSlice(data[dynamicOffset:]) if err != nil { @@ -1461,15 +1498,19 @@ func (t *TotalSupply0Call) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -1641,8 +1682,9 @@ func (t *TransferFromCall) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 128 // Decode static field From: address @@ -1662,9 +1704,12 @@ func (t *TransferFromCall) Decode(data []byte) (int, error) { } // Decode dynamic field Denom { - offset := int(binary.BigEndian.Uint64(data[96+24 : 96+32])) + offset, err = abi.DecodeSize(data[96:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Denom") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Denom, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { diff --git a/precompiles/bank/erc20/abi.go b/precompiles/bank/erc20/abi.go index 26ce340a8..c25b2511c 100644 --- a/precompiles/bank/erc20/abi.go +++ b/precompiles/bank/erc20/abi.go @@ -4,8 +4,6 @@ package erc20 import ( "encoding/binary" - "errors" - "fmt" "io" "math/big" @@ -367,15 +365,19 @@ func (t *NameReturn) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Name { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Name") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Name, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -476,15 +478,19 @@ func (t *SymbolReturn) Decode(data []byte) (int, error) { return 0, io.ErrUnexpectedEOF } var ( - err error - n int + err error + n int + offset int ) dynamicOffset := 32 // Decode dynamic field Symbol { - offset := int(binary.BigEndian.Uint64(data[0+24 : 0+32])) + offset, err = abi.DecodeSize(data[0:]) + if err != nil { + return 0, err + } if offset != dynamicOffset { - return 0, errors.New("invalid offset for dynamic field Symbol") + return 0, abi.ErrInvalidOffsetForDynamicField } t.Symbol, n, err = abi.DecodeString(data[dynamicOffset:]) if err != nil { @@ -988,10 +994,10 @@ func (e ApprovalEventIndexed) EncodeTopics() ([]common.Hash, error) { // 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 fmt.Errorf("invalid number of topics for Approval event: expected 3, got %d", len(topics)) + return abi.ErrInvalidNumberOfTopics } if topics[0] != ApprovalEventTopic { - return fmt.Errorf("invalid event topic for Approval event") + return abi.ErrInvalidEventTopic } var err error e.Owner, _, err = abi.DecodeAddress(topics[1][:]) @@ -1126,10 +1132,10 @@ func (e TransferEventIndexed) EncodeTopics() ([]common.Hash, error) { // 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 fmt.Errorf("invalid number of topics for Transfer event: expected 3, got %d", len(topics)) + return abi.ErrInvalidNumberOfTopics } if topics[0] != TransferEventTopic { - return fmt.Errorf("invalid event topic for Transfer event") + return abi.ErrInvalidEventTopic } var err error e.From, _, err = abi.DecodeAddress(topics[1][:]) From d73aa041ef9048229d68036c978d8d61d35868c4 Mon Sep 17 00:00:00 2001 From: yihuang Date: Sat, 15 Nov 2025 00:17:47 +0800 Subject: [PATCH 10/14] fix systemtests --- tests/systemtests/go.mod | 2 +- tests/systemtests/go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index f0bbfa921..1495ec63a 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 6b43e1b68..6510647ff 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -912,6 +912,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.0 h1:T618RtH5cdpfUUPAoc/581R0Hw3zPDBL8lXELINAn8A= +github.com/yihuang/go-abi v0.1.0/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= From bff6d52c1ec51a841a8c6a19ed836f5e4b8438a8 Mon Sep 17 00:00:00 2001 From: yihuang Date: Tue, 18 Nov 2025 23:17:05 +0800 Subject: [PATCH 11/14] use go-abi 0.1.1 --- evmd/go.mod | 2 +- evmd/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/evmd/go.mod b/evmd/go.mod index 544db5c83..32752cfab 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -242,7 +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.0 // 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 8f2c47c40..2608e827f 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -1004,8 +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.0 h1:T618RtH5cdpfUUPAoc/581R0Hw3zPDBL8lXELINAn8A= -github.com/yihuang/go-abi v0.1.0/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= +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 e27fe1b81..023121485 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +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.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.44.0 diff --git a/go.sum b/go.sum index a8ca71850..dd2efd492 100644 --- a/go.sum +++ b/go.sum @@ -984,8 +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.0 h1:T618RtH5cdpfUUPAoc/581R0Hw3zPDBL8lXELINAn8A= -github.com/yihuang/go-abi v0.1.0/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= +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= From aacf2bb7e8d02d963264400d6b8b22622ea8aaa5 Mon Sep 17 00:00:00 2001 From: yihuang Date: Tue, 18 Nov 2025 23:26:45 +0800 Subject: [PATCH 12/14] go mod tidy --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 023121485..ee02f2c14 100644 --- a/go.mod +++ b/go.mod @@ -267,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 dd2efd492..fa838a66d 100644 --- a/go.sum +++ b/go.sum @@ -1093,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= From dad889880df229a05c11391c3ce713ac1aa92251 Mon Sep 17 00:00:00 2001 From: yihuang Date: Tue, 18 Nov 2025 23:27:31 +0800 Subject: [PATCH 13/14] tidy --- tests/speedtest/go.mod | 3 ++- tests/speedtest/go.sum | 4 ++++ tests/systemtests/go.sum | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/speedtest/go.mod b/tests/speedtest/go.mod index 2bbfce48d..dba376a15 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.20251117181803-4c280784c00e 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/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect diff --git a/tests/speedtest/go.sum b/tests/speedtest/go.sum index 51bd2233c..d90b251d9 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.sum b/tests/systemtests/go.sum index e3ef4fe25..40a0d183c 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -911,8 +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.0 h1:T618RtH5cdpfUUPAoc/581R0Hw3zPDBL8lXELINAn8A= -github.com/yihuang/go-abi v0.1.0/go.mod h1:btymTlqoiLCR8Gj5bppalyNPSzQYUfK6YROYsihjGS4= +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= From aa1cdac4cc543f188508160a61d37b46962b4223 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 20 Nov 2025 10:02:12 +0800 Subject: [PATCH 14/14] ignore generated abi files from code coverage --- Makefile | 2 +- precompiles/bank/bank_test.go | 2 +- precompiles/bank/erc20/{abi.go => erc20.abi.go} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename precompiles/bank/erc20/{abi.go => erc20.abi.go} (100%) 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/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index 08581770f..766e90767 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -28,7 +28,7 @@ import ( 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/abi.go +//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)", diff --git a/precompiles/bank/erc20/abi.go b/precompiles/bank/erc20/erc20.abi.go similarity index 100% rename from precompiles/bank/erc20/abi.go rename to precompiles/bank/erc20/erc20.abi.go