├── .github └── workflows │ ├── build.yml │ ├── coverage.yml │ └── pull_request.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── call.go ├── call_test.go ├── caller.go ├── caller_test.go ├── contracts └── contract_multicall │ ├── abi.json │ ├── interface.go │ └── multicall.go ├── examples ├── agent_registry │ └── main.go └── balance │ └── main.go ├── go.mod └── go.sum /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | jobs: 8 | go: 9 | name: Validate 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | - name: Setup Go 15 | uses: actions/setup-go@v4 16 | with: 17 | go-version: '1.19' 18 | cache: false 19 | - name: Test 20 | run: make test 21 | - name: Lint 22 | uses: golangci/golangci-lint-action@v3 23 | with: 24 | skip-go-installation: true 25 | skip-pkg-cache: true 26 | skip-build-cache: true 27 | version: v1.52.2 28 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | name: Update coverage badge 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 0 16 | - name: Setup Go 17 | uses: actions/setup-go@v4 18 | with: 19 | go-version: '1.19' 20 | cache: false 21 | - name: Run Test 22 | run: make cover 23 | - name: Go Coverage Badge 24 | uses: tj-actions/coverage-badge-go@v2 25 | with: 26 | text: coverage 27 | filename: coverage.out 28 | - name: Verify Changed files 29 | uses: tj-actions/verify-changed-files@v12 30 | id: verify-changed-files 31 | with: 32 | files: README.md 33 | - name: Commit changes 34 | if: steps.verify-changed-files.outputs.files_changed == 'true' 35 | run: | 36 | git config --local user.email "action@github.com" 37 | git config --local user.name "GitHub Action" 38 | git add README.md 39 | git commit -m "chore: update coverage badge" 40 | - name: Push changes 41 | if: steps.verify-changed-files.outputs.files_changed == 'true' 42 | uses: ad-m/github-push-action@master 43 | with: 44 | github_token: ${{ github.token }} 45 | branch: ${{ github.head_ref }} 46 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: PR 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | go: 8 | name: Validate 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | - uses: actions/setup-go@v4 14 | with: 15 | go-version: '1.19' 16 | cache: false 17 | - name: Test 18 | run: make test 19 | - name: Lint 20 | uses: golangci/golangci-lint-action@v3 21 | with: 22 | skip-go-installation: true 23 | skip-pkg-cache: true 24 | skip-build-cache: true 25 | version: v1.52.2 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | toolbin 2 | coverage.out 3 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | gosimple: 3 | go: "1.19" 4 | 5 | staticcheck: 6 | go: "1.19" 7 | 8 | stylecheck: 9 | go: "1.19" 10 | 11 | unused: 12 | go: "1.19" 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2023 Forta Foundation and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export GOBIN = $(shell pwd)/toolbin 2 | 3 | LINT = $(GOBIN)/golangci-lint 4 | FORMAT = $(GOBIN)/goimports 5 | 6 | ABIGEN = $(GOBIN)/abigen 7 | 8 | .PHONY: tools 9 | tools: 10 | @echo 'Installing tools...' 11 | @rm -rf toolbin 12 | @go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.52.2 13 | @go install golang.org/x/tools/cmd/goimports@v0.1.11 14 | 15 | @go install github.com/ethereum/go-ethereum/cmd/abigen@v1.11.5 16 | 17 | .PHONY: require-tools 18 | require-tools: tools 19 | @echo 'Checking installed tools...' 20 | @file $(LINT) > /dev/null 21 | @file $(FORMAT) > /dev/null 22 | 23 | @file $(ABIGEN) > /dev/null 24 | 25 | @echo "All tools found in $(GOBIN)!" 26 | 27 | .PHONY: generate 28 | generate: require-tools 29 | @$(ABIGEN) --out contracts/contract_multicall/multicall.go \ 30 | --abi contracts/contract_multicall/abi.json --pkg contract_multicall \ 31 | --type Multicall 32 | 33 | .PHONY: test 34 | test: 35 | go test -v -count=1 -covermode=count -coverprofile=coverage.out 36 | 37 | .PHONY: cover 38 | cover: test 39 | go tool cover -func=coverage.out -o=coverage.out 40 | 41 | .PHONY: coverage 42 | coverage: test 43 | go tool cover -func=coverage.out | grep total | awk '{print substr($$3, 1, length($$3)-1)}' 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-multicall 2 | ![coverage](https://img.shields.io/badge/coverage-87.7%25-brightgreen) 3 | ![build](https://github.com/forta-network/go-multicall/actions/workflows/build.yml/badge.svg) 4 | 5 | A thin Go client for making multiple function calls in single `eth_call` request 6 | 7 | - Uses the go-ethereum tools and libraries 8 | - Interfaces with the [MakerDAO `Multicall3` contract](https://github.com/mds1/multicall) 9 | 10 | _**Warning:** MakerDAO Multicall contracts are different than the [OpenZeppelin Multicall contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Multicall.sol). Please see [this thread](https://forum.openzeppelin.com/t/multicall-by-oz-and-makerdao-has-a-difference/9350) in the OpenZeppelin forum if you are looking for an explanation._ 11 | 12 | ## Install 13 | 14 | ``` 15 | go get github.com/forta-network/go-multicall 16 | ``` 17 | 18 | ## Example 19 | 20 | (See other examples under the `examples` directory!) 21 | 22 | ```go 23 | package main 24 | 25 | import ( 26 | "context" 27 | "fmt" 28 | "math/big" 29 | 30 | "github.com/forta-network/go-multicall" 31 | "github.com/ethereum/go-ethereum/common" 32 | ) 33 | 34 | const ( 35 | APIURL = "https://cloudflare-eth.com" 36 | ERC20ABI = `[ 37 | { 38 | "constant":true, 39 | "inputs":[ 40 | { 41 | "name":"tokenOwner", 42 | "type":"address" 43 | } 44 | ], 45 | "name":"balanceOf", 46 | "outputs":[ 47 | { 48 | "name":"balance", 49 | "type":"uint256" 50 | } 51 | ], 52 | "payable":false, 53 | "stateMutability":"view", 54 | "type":"function" 55 | } 56 | ]` 57 | ) 58 | 59 | type balanceOutput struct { 60 | Balance *big.Int 61 | } 62 | 63 | func main() { 64 | caller, err := multicall.Dial(context.Background(), APIURL) 65 | if err != nil { 66 | panic(err) 67 | } 68 | 69 | contract, err := multicall.NewContract(ERC20ABI, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") 70 | if err != nil { 71 | panic(err) 72 | } 73 | 74 | calls, err := caller.Call(nil, 75 | contract.NewCall( 76 | new(balanceOutput), 77 | "balanceOf", 78 | common.HexToAddress("0xcEe284F754E854890e311e3280b767F80797180d"), // Arbitrum One gateway 79 | ).Name("Arbitrum One gateway balance"), 80 | contract.NewCall( 81 | new(balanceOutput), 82 | "balanceOf", 83 | common.HexToAddress("0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf"), // Polygon ERC20 bridge 84 | ).Name("Polygon ERC20 bridge balance"), 85 | ) 86 | if err != nil { 87 | panic(err) 88 | } 89 | for _, call := range calls { 90 | fmt.Println(call.CallName, ":", call.Outputs.(*balanceOutput).Balance) 91 | } 92 | } 93 | ``` 94 | -------------------------------------------------------------------------------- /call.go: -------------------------------------------------------------------------------- 1 | package multicall 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | 9 | "github.com/ethereum/go-ethereum/accounts/abi" 10 | "github.com/ethereum/go-ethereum/common" 11 | ) 12 | 13 | // Contract wraps the parsed ABI and acts as a call factory. 14 | type Contract struct { 15 | ABI *abi.ABI 16 | Address common.Address 17 | } 18 | 19 | // NewContract creates a new call factory. 20 | func NewContract(rawJson, address string) (*Contract, error) { 21 | parsedABI, err := ParseABI(rawJson) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return &Contract{ 26 | ABI: parsedABI, 27 | Address: common.HexToAddress(address), 28 | }, nil 29 | } 30 | 31 | // ParseABI parses raw ABI JSON. 32 | func ParseABI(rawJson string) (*abi.ABI, error) { 33 | parsed, err := abi.JSON(bytes.NewBufferString(rawJson)) 34 | if err != nil { 35 | return nil, fmt.Errorf("failed to parse abi: %v", err) 36 | } 37 | return &parsed, nil 38 | } 39 | 40 | // Call wraps a multicall call. 41 | type Call struct { 42 | CallName string 43 | Contract *Contract 44 | Method string 45 | Inputs []any 46 | Outputs any 47 | CanFail bool 48 | Failed bool 49 | } 50 | 51 | // NewCall creates a new call using given inputs. 52 | // Outputs type is the expected output struct to unpack and set values in. 53 | func (contract *Contract) NewCall( 54 | outputs any, methodName string, inputs ...any, 55 | ) *Call { 56 | return &Call{ 57 | Contract: contract, 58 | Method: methodName, 59 | Inputs: inputs, 60 | Outputs: outputs, 61 | } 62 | } 63 | 64 | // Name sets a name for the call. 65 | func (call *Call) Name(name string) *Call { 66 | call.CallName = name 67 | return call 68 | } 69 | 70 | // AllowFailure sets if the call is allowed to fail. This helps avoiding a revert 71 | // when one of the calls in the array fails. 72 | func (call *Call) AllowFailure() *Call { 73 | call.CanFail = true 74 | return call 75 | } 76 | 77 | // Unpack unpacks and converts EVM outputs and sets struct fields. 78 | func (call *Call) Unpack(b []byte) error { 79 | t := reflect.ValueOf(call.Outputs) 80 | if t.Kind() == reflect.Pointer { 81 | t = t.Elem() 82 | } 83 | if t.Kind() != reflect.Struct { 84 | return errors.New("outputs type is not a struct") 85 | } 86 | 87 | out, err := call.Contract.ABI.Unpack(call.Method, b) 88 | if err != nil { 89 | return fmt.Errorf("failed to unpack '%s' outputs: %v", call.Method, err) 90 | } 91 | 92 | fieldCount := t.NumField() 93 | for i := 0; i < fieldCount; i++ { 94 | field := t.Field(i) 95 | converted := abi.ConvertType(out[i], field.Interface()) 96 | field.Set(reflect.ValueOf(converted)) 97 | } 98 | 99 | return nil 100 | } 101 | 102 | // Pack converts and packs EVM inputs. 103 | func (call *Call) Pack() ([]byte, error) { 104 | b, err := call.Contract.ABI.Pack(call.Method, call.Inputs...) 105 | if err != nil { 106 | return nil, fmt.Errorf("failed to pack '%s' inputs: %v", call.Method, err) 107 | } 108 | return b, nil 109 | } 110 | -------------------------------------------------------------------------------- /call_test.go: -------------------------------------------------------------------------------- 1 | package multicall 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestCall_BadABI(t *testing.T) { 10 | r := require.New(t) 11 | 12 | const oneValueABI = `[ 13 | { 14 | "constant":true, 15 | "inputs": [ 16 | { 17 | "name":"val1", 18 | "type":"bool" 19 | } 20 | ], 21 | "name":"testFunc", 22 | "outputs": [ 23 | { 24 | "name":"val1", 25 | "type":"bool" 26 | } 27 | ], 28 | "payable":false, 29 | "stateMutability":"view", 30 | "type":"function" 31 | } 32 | ` // missing closing ] at the end 33 | 34 | _, err := NewContract(oneValueABI, "0x") 35 | r.Error(err) 36 | r.ErrorContains(err, "unexpected EOF") 37 | } 38 | -------------------------------------------------------------------------------- /caller.go: -------------------------------------------------------------------------------- 1 | package multicall 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/ethereum/go-ethereum/ethclient" 11 | "github.com/forta-network/go-multicall/contracts/contract_multicall" 12 | ) 13 | 14 | // DefaultAddress is the same for all chains (Multicall3). 15 | // Taken from https://github.com/mds1/multicall 16 | const DefaultAddress = "0xcA11bde05977b3631167028862bE2a173976CA11" 17 | 18 | // Caller makes multicalls. 19 | type Caller struct { 20 | contract contract_multicall.Interface 21 | } 22 | 23 | // New creates a new caller. 24 | func New(client bind.ContractCaller, multicallAddr ...string) (*Caller, error) { 25 | addr := DefaultAddress 26 | if multicallAddr != nil { 27 | addr = multicallAddr[0] 28 | } 29 | contract, err := contract_multicall.NewMulticallCaller(common.HexToAddress(addr), client) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &Caller{ 34 | contract: contract, 35 | }, nil 36 | } 37 | 38 | // Dial dials and Ethereum JSON-RPC API and uses the client as the 39 | // caller backend. 40 | func Dial(ctx context.Context, rawUrl string, multicallAddr ...string) (*Caller, error) { 41 | client, err := ethclient.DialContext(ctx, rawUrl) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return New(client, multicallAddr...) 46 | } 47 | 48 | // Call makes multicalls. 49 | func (caller *Caller) Call(opts *bind.CallOpts, calls ...*Call) ([]*Call, error) { 50 | var multiCalls []contract_multicall.Multicall3Call3 51 | 52 | for i, call := range calls { 53 | b, err := call.Pack() 54 | if err != nil { 55 | return calls, fmt.Errorf("failed to pack call inputs at index [%d]: %v", i, err) 56 | } 57 | multiCalls = append(multiCalls, contract_multicall.Multicall3Call3{ 58 | Target: call.Contract.Address, 59 | AllowFailure: call.CanFail, 60 | CallData: b, 61 | }) 62 | } 63 | 64 | results, err := caller.contract.Aggregate3(opts, multiCalls) 65 | if err != nil { 66 | return calls, fmt.Errorf("multicall failed: %v", err) 67 | } 68 | 69 | for i, result := range results { 70 | call := calls[i] // index always matches 71 | call.Failed = !result.Success 72 | if err := call.Unpack(result.ReturnData); err != nil { 73 | return calls, fmt.Errorf("failed to unpack call outputs at index [%d]: %v", i, err) 74 | } 75 | } 76 | 77 | return calls, nil 78 | } 79 | 80 | // CallChunked makes multiple multicalls by chunking given calls. 81 | // Cooldown is helpful for sleeping between chunks and avoiding rate limits. 82 | func (caller *Caller) CallChunked(opts *bind.CallOpts, chunkSize int, cooldown time.Duration, calls ...*Call) ([]*Call, error) { 83 | var allCalls []*Call 84 | for i, chunk := range chunkInputs(chunkSize, calls) { 85 | if i > 0 && cooldown > 0 { 86 | time.Sleep(cooldown) 87 | } 88 | 89 | chunk, err := caller.Call(opts, chunk...) 90 | if err != nil { 91 | return calls, fmt.Errorf("call chunk [%d] failed: %v", i, err) 92 | } 93 | allCalls = append(allCalls, chunk...) 94 | } 95 | return allCalls, nil 96 | } 97 | 98 | func chunkInputs[T any](chunkSize int, inputs []T) (chunks [][]T) { 99 | if len(inputs) == 0 { 100 | return 101 | } 102 | 103 | if chunkSize <= 0 || len(inputs) < 2 || chunkSize > len(inputs) { 104 | return [][]T{inputs} 105 | } 106 | 107 | lastChunkSize := len(inputs) % chunkSize 108 | 109 | chunkCount := len(inputs) / chunkSize 110 | 111 | for i := 0; i < chunkCount; i++ { 112 | start := i * chunkSize 113 | end := start + chunkSize 114 | chunks = append(chunks, inputs[start:end]) 115 | } 116 | 117 | if lastChunkSize > 0 { 118 | start := chunkCount * chunkSize 119 | end := start + lastChunkSize 120 | chunks = append(chunks, inputs[start:end]) 121 | } 122 | 123 | return 124 | } 125 | -------------------------------------------------------------------------------- /caller_test.go: -------------------------------------------------------------------------------- 1 | package multicall 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | "testing" 7 | 8 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/forta-network/go-multicall/contracts/contract_multicall" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | type testType struct { 15 | Val1 bool 16 | Val2 string 17 | Val3 []string 18 | Val4 []*big.Int 19 | Val5 *big.Int 20 | Val6 common.Address 21 | } 22 | 23 | const ( 24 | testAddr1 = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" 25 | testAddr2 = "0x64d5192F03bD98dB1De2AA8B4abAC5419eaC32CE" 26 | ) 27 | 28 | const testABI = `[ 29 | { 30 | "constant":true, 31 | "inputs":[ 32 | { 33 | "name":"val1", 34 | "type":"bool" 35 | }, 36 | { 37 | "name":"val2", 38 | "type":"string" 39 | }, 40 | { 41 | "name":"val1", 42 | "type":"string[]" 43 | }, 44 | { 45 | "name":"val4", 46 | "type":"uint256[]" 47 | }, 48 | { 49 | "name":"val5", 50 | "type":"uint256" 51 | }, 52 | { 53 | "name":"val6", 54 | "type":"address" 55 | } 56 | ], 57 | "name":"testFunc", 58 | "outputs":[ 59 | { 60 | "name":"val1", 61 | "type":"bool" 62 | }, 63 | { 64 | "name":"val2", 65 | "type":"string" 66 | }, 67 | { 68 | "name":"val1", 69 | "type":"string[]" 70 | }, 71 | { 72 | "name":"val4", 73 | "type":"uint256[]" 74 | }, 75 | { 76 | "name":"val5", 77 | "type":"uint256" 78 | }, 79 | { 80 | "name":"val6", 81 | "type":"address" 82 | } 83 | ], 84 | "payable":false, 85 | "stateMutability":"view", 86 | "type":"function" 87 | } 88 | ]` 89 | 90 | type multicallStub struct { 91 | returnData func(calls []contract_multicall.Multicall3Call3) [][]byte 92 | } 93 | 94 | func (ms *multicallStub) Aggregate3(opts *bind.CallOpts, calls []contract_multicall.Multicall3Call3) (results []contract_multicall.Multicall3Result, err error) { 95 | allReturnData := ms.returnData(calls) 96 | for _, returnData := range allReturnData { 97 | results = append(results, contract_multicall.Multicall3Result{ 98 | Success: true, 99 | ReturnData: returnData, 100 | }) 101 | } 102 | return 103 | } 104 | 105 | func TestCaller_TwoCalls(t *testing.T) { 106 | r := require.New(t) 107 | 108 | testContract1, err := NewContract(testABI, testAddr1) 109 | r.NoError(err) 110 | 111 | testContract2, err := NewContract(testABI, testAddr2) 112 | r.NoError(err) 113 | 114 | values1 := testType{ 115 | Val1: true, 116 | Val2: "val2", 117 | Val3: []string{"val3_1", "val3_2"}, 118 | Val4: []*big.Int{big.NewInt(123), big.NewInt(456)}, 119 | Val5: big.NewInt(678), 120 | Val6: common.HexToAddress(testAddr1), 121 | } 122 | 123 | call1 := testContract1.NewCall( 124 | new(testType), "testFunc", 125 | values1.Val1, values1.Val2, values1.Val3, 126 | values1.Val4, values1.Val5, values1.Val6, 127 | ) 128 | 129 | values2 := testType{ 130 | Val1: false, 131 | Val2: "val2_alt", 132 | Val3: []string{"val3_1_alt", "val3_2_alt"}, 133 | Val4: []*big.Int{big.NewInt(1239), big.NewInt(4569)}, 134 | Val5: big.NewInt(6789), 135 | Val6: common.HexToAddress(testAddr2), 136 | } 137 | 138 | call2 := testContract2.NewCall( 139 | new(testType), "testFunc", 140 | values2.Val1, values2.Val2, values2.Val3, 141 | values2.Val4, values2.Val5, values2.Val6, 142 | ) 143 | 144 | caller := &Caller{ 145 | contract: &multicallStub{ 146 | returnData: func(calls []contract_multicall.Multicall3Call3) [][]byte { 147 | return [][]byte{ 148 | // return inputs as outputs by stripping the method prefix 149 | calls[0].CallData[4:], 150 | } 151 | }, 152 | }, 153 | } 154 | 155 | calls, err := caller.CallChunked(nil, 1, 0, call1, call2) 156 | r.NoError(err) 157 | 158 | call1Out := calls[0].Outputs.(*testType) 159 | r.Equal(values1.Val1, call1Out.Val1) 160 | r.Equal(values1.Val2, call1Out.Val2) 161 | r.Equal(values1.Val3, call1Out.Val3) 162 | r.Equal(values1.Val4, call1Out.Val4) 163 | r.Equal(values1.Val5, call1Out.Val5) 164 | r.Equal(values1.Val6, call1Out.Val6) 165 | 166 | call2Out := calls[1].Outputs.(*testType) 167 | r.Equal(values2.Val1, call2Out.Val1) 168 | r.Equal(values2.Val2, call2Out.Val2) 169 | r.Equal(values2.Val3, call2Out.Val3) 170 | r.Equal(values2.Val4, call2Out.Val4) 171 | r.Equal(values2.Val5, call2Out.Val5) 172 | r.Equal(values2.Val6, call2Out.Val6) 173 | } 174 | 175 | const emptyABI = `[ 176 | { 177 | "constant":true, 178 | "inputs": [], 179 | "name":"testFunc", 180 | "outputs": [], 181 | "payable":false, 182 | "stateMutability":"view", 183 | "type":"function" 184 | } 185 | ]` 186 | 187 | func TestCaller_EmptyCall(t *testing.T) { 188 | r := require.New(t) 189 | 190 | testContract, err := NewContract(emptyABI, testAddr1) 191 | r.NoError(err) 192 | 193 | call := testContract.NewCall( 194 | new(struct{}), "testFunc", 195 | // no inputs 196 | ) 197 | 198 | caller := &Caller{ 199 | contract: &multicallStub{ 200 | returnData: func(calls []contract_multicall.Multicall3Call3) [][]byte { 201 | return [][]byte{ 202 | // return empty output 203 | make([]byte, 0), 204 | } 205 | }, 206 | }, 207 | } 208 | 209 | calls, err := caller.CallChunked(nil, 1, 0, call) 210 | r.NoError(err) 211 | r.Len(calls, 1) 212 | } 213 | 214 | const oneValueABI = `[ 215 | { 216 | "constant":true, 217 | "inputs": [ 218 | { 219 | "name":"val1", 220 | "type":"bool" 221 | } 222 | ], 223 | "name":"testFunc", 224 | "outputs": [ 225 | { 226 | "name":"val1", 227 | "type":"bool" 228 | } 229 | ], 230 | "payable":false, 231 | "stateMutability":"view", 232 | "type":"function" 233 | } 234 | ]` 235 | 236 | func TestCaller_BadInput(t *testing.T) { 237 | r := require.New(t) 238 | 239 | testContract, err := NewContract(oneValueABI, testAddr1) 240 | r.NoError(err) 241 | 242 | call := testContract.NewCall( 243 | new(struct{}), "testFunc", 244 | 'a', 245 | ) 246 | 247 | caller := &Caller{ 248 | contract: &multicallStub{ 249 | returnData: func(calls []contract_multicall.Multicall3Call3) [][]byte { 250 | return [][]byte{ 251 | // return bad output 252 | {}, 253 | } 254 | }, 255 | }, 256 | } 257 | 258 | calls, err := caller.Call(nil, call) 259 | r.Error(err) 260 | r.ErrorContains(err, "cannot use") 261 | r.Len(calls, 1) 262 | } 263 | 264 | func TestCaller_BadOutput(t *testing.T) { 265 | r := require.New(t) 266 | 267 | testContract, err := NewContract(emptyABI, testAddr1) 268 | r.NoError(err) 269 | 270 | call := testContract.NewCall( 271 | new(struct{}), "testFunc", 272 | // no inputs 273 | ) 274 | 275 | caller := &Caller{ 276 | contract: &multicallStub{ 277 | returnData: func(calls []contract_multicall.Multicall3Call3) [][]byte { 278 | return [][]byte{ 279 | // return bad output 280 | {'a'}, 281 | } 282 | }, 283 | }, 284 | } 285 | 286 | calls, err := caller.Call(nil, call) 287 | r.Error(err) 288 | r.Len(calls, 1) 289 | } 290 | 291 | func TestCaller_WrongOutputsType(t *testing.T) { 292 | r := require.New(t) 293 | 294 | testContract, err := NewContract(oneValueABI, testAddr1) 295 | r.NoError(err) 296 | 297 | call := testContract.NewCall( 298 | new([]struct{}), "testFunc", 299 | true, 300 | ) 301 | 302 | packedOutput, err := testContract.ABI.Pack("testFunc", true) 303 | r.NoError(err) 304 | 305 | caller := &Caller{ 306 | contract: &multicallStub{ 307 | returnData: func(calls []contract_multicall.Multicall3Call3) [][]byte { 308 | return [][]byte{ 309 | packedOutput, 310 | } 311 | }, 312 | }, 313 | } 314 | 315 | calls, err := caller.Call(nil, call) 316 | r.Error(err) 317 | r.ErrorContains(err, "not a struct") 318 | r.Len(calls, 1) 319 | } 320 | 321 | func TestDial(t *testing.T) { 322 | r := require.New(t) 323 | 324 | caller, err := Dial(context.Background(), "https://polygon-rpc.com") 325 | r.NoError(err) 326 | r.NotNil(caller) 327 | } 328 | 329 | func TestChunkInputs(t *testing.T) { 330 | testCases := []struct { 331 | name string 332 | chunkSize int 333 | inputs []int 334 | expected [][]int 335 | }{ 336 | { 337 | name: "zero inputs large chunk size", 338 | chunkSize: 12345, 339 | inputs: []int{}, 340 | expected: nil, 341 | }, 342 | { 343 | name: "single input large chunk size", 344 | chunkSize: 12345, 345 | inputs: []int{10}, 346 | expected: [][]int{{10}}, 347 | }, 348 | { 349 | name: "2 inputs chunk size 1", 350 | chunkSize: 1, 351 | inputs: []int{10, 20}, 352 | expected: [][]int{{10}, {20}}, 353 | }, 354 | { 355 | name: "2 inputs chunk size 2", 356 | chunkSize: 2, 357 | inputs: []int{10, 20}, 358 | expected: [][]int{{10, 20}}, 359 | }, 360 | { 361 | name: "5 inputs chunk size 3", 362 | chunkSize: 3, 363 | inputs: []int{10, 20, 30, 40, 50}, 364 | expected: [][]int{{10, 20, 30}, {40, 50}}, 365 | }, 366 | { 367 | name: "3 inputs chunk size 5", 368 | chunkSize: 5, 369 | inputs: []int{10, 20, 30}, 370 | expected: [][]int{{10, 20, 30}}, 371 | }, 372 | } 373 | 374 | for _, testCase := range testCases { 375 | t.Run(testCase.name, func(t *testing.T) { 376 | r := require.New(t) 377 | 378 | r.Equal(testCase.expected, chunkInputs(testCase.chunkSize, testCase.inputs)) 379 | }) 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /contracts/contract_multicall/abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs":[ 4 | { 5 | "components":[ 6 | { 7 | "internalType":"address", 8 | "name":"target", 9 | "type":"address" 10 | }, 11 | { 12 | "internalType":"bytes", 13 | "name":"callData", 14 | "type":"bytes" 15 | } 16 | ], 17 | "internalType":"struct Multicall3.Call[]", 18 | "name":"calls", 19 | "type":"tuple[]" 20 | } 21 | ], 22 | "name":"aggregate", 23 | "outputs":[ 24 | { 25 | "internalType":"uint256", 26 | "name":"blockNumber", 27 | "type":"uint256" 28 | }, 29 | { 30 | "internalType":"bytes[]", 31 | "name":"returnData", 32 | "type":"bytes[]" 33 | } 34 | ], 35 | "stateMutability":"view", 36 | "type":"function" 37 | }, 38 | { 39 | "inputs":[ 40 | { 41 | "components":[ 42 | { 43 | "internalType":"address", 44 | "name":"target", 45 | "type":"address" 46 | }, 47 | { 48 | "internalType":"bool", 49 | "name":"allowFailure", 50 | "type":"bool" 51 | }, 52 | { 53 | "internalType":"bytes", 54 | "name":"callData", 55 | "type":"bytes" 56 | } 57 | ], 58 | "internalType":"struct Multicall3.Call3[]", 59 | "name":"calls", 60 | "type":"tuple[]" 61 | } 62 | ], 63 | "name":"aggregate3", 64 | "outputs":[ 65 | { 66 | "components":[ 67 | { 68 | "internalType":"bool", 69 | "name":"success", 70 | "type":"bool" 71 | }, 72 | { 73 | "internalType":"bytes", 74 | "name":"returnData", 75 | "type":"bytes" 76 | } 77 | ], 78 | "internalType":"struct Multicall3.Result[]", 79 | "name":"returnData", 80 | "type":"tuple[]" 81 | } 82 | ], 83 | "stateMutability":"view", 84 | "type":"function" 85 | }, 86 | { 87 | "inputs":[ 88 | { 89 | "components":[ 90 | { 91 | "internalType":"address", 92 | "name":"target", 93 | "type":"address" 94 | }, 95 | { 96 | "internalType":"bool", 97 | "name":"allowFailure", 98 | "type":"bool" 99 | }, 100 | { 101 | "internalType":"uint256", 102 | "name":"value", 103 | "type":"uint256" 104 | }, 105 | { 106 | "internalType":"bytes", 107 | "name":"callData", 108 | "type":"bytes" 109 | } 110 | ], 111 | "internalType":"struct Multicall3.Call3Value[]", 112 | "name":"calls", 113 | "type":"tuple[]" 114 | } 115 | ], 116 | "name":"aggregate3Value", 117 | "outputs":[ 118 | { 119 | "components":[ 120 | { 121 | "internalType":"bool", 122 | "name":"success", 123 | "type":"bool" 124 | }, 125 | { 126 | "internalType":"bytes", 127 | "name":"returnData", 128 | "type":"bytes" 129 | } 130 | ], 131 | "internalType":"struct Multicall3.Result[]", 132 | "name":"returnData", 133 | "type":"tuple[]" 134 | } 135 | ], 136 | "stateMutability":"view", 137 | "type":"function" 138 | }, 139 | { 140 | "inputs":[ 141 | { 142 | "components":[ 143 | { 144 | "internalType":"address", 145 | "name":"target", 146 | "type":"address" 147 | }, 148 | { 149 | "internalType":"bytes", 150 | "name":"callData", 151 | "type":"bytes" 152 | } 153 | ], 154 | "internalType":"struct Multicall3.Call[]", 155 | "name":"calls", 156 | "type":"tuple[]" 157 | } 158 | ], 159 | "name":"blockAndAggregate", 160 | "outputs":[ 161 | { 162 | "internalType":"uint256", 163 | "name":"blockNumber", 164 | "type":"uint256" 165 | }, 166 | { 167 | "internalType":"bytes32", 168 | "name":"blockHash", 169 | "type":"bytes32" 170 | }, 171 | { 172 | "components":[ 173 | { 174 | "internalType":"bool", 175 | "name":"success", 176 | "type":"bool" 177 | }, 178 | { 179 | "internalType":"bytes", 180 | "name":"returnData", 181 | "type":"bytes" 182 | } 183 | ], 184 | "internalType":"struct Multicall3.Result[]", 185 | "name":"returnData", 186 | "type":"tuple[]" 187 | } 188 | ], 189 | "stateMutability":"view", 190 | "type":"function" 191 | }, 192 | { 193 | "inputs":[ 194 | 195 | ], 196 | "name":"getBasefee", 197 | "outputs":[ 198 | { 199 | "internalType":"uint256", 200 | "name":"basefee", 201 | "type":"uint256" 202 | } 203 | ], 204 | "stateMutability":"view", 205 | "type":"function" 206 | }, 207 | { 208 | "inputs":[ 209 | { 210 | "internalType":"uint256", 211 | "name":"blockNumber", 212 | "type":"uint256" 213 | } 214 | ], 215 | "name":"getBlockHash", 216 | "outputs":[ 217 | { 218 | "internalType":"bytes32", 219 | "name":"blockHash", 220 | "type":"bytes32" 221 | } 222 | ], 223 | "stateMutability":"view", 224 | "type":"function" 225 | }, 226 | { 227 | "inputs":[ 228 | 229 | ], 230 | "name":"getBlockNumber", 231 | "outputs":[ 232 | { 233 | "internalType":"uint256", 234 | "name":"blockNumber", 235 | "type":"uint256" 236 | } 237 | ], 238 | "stateMutability":"view", 239 | "type":"function" 240 | }, 241 | { 242 | "inputs":[ 243 | 244 | ], 245 | "name":"getChainId", 246 | "outputs":[ 247 | { 248 | "internalType":"uint256", 249 | "name":"chainid", 250 | "type":"uint256" 251 | } 252 | ], 253 | "stateMutability":"view", 254 | "type":"function" 255 | }, 256 | { 257 | "inputs":[ 258 | 259 | ], 260 | "name":"getCurrentBlockCoinbase", 261 | "outputs":[ 262 | { 263 | "internalType":"address", 264 | "name":"coinbase", 265 | "type":"address" 266 | } 267 | ], 268 | "stateMutability":"view", 269 | "type":"function" 270 | }, 271 | { 272 | "inputs":[ 273 | 274 | ], 275 | "name":"getCurrentBlockDifficulty", 276 | "outputs":[ 277 | { 278 | "internalType":"uint256", 279 | "name":"difficulty", 280 | "type":"uint256" 281 | } 282 | ], 283 | "stateMutability":"view", 284 | "type":"function" 285 | }, 286 | { 287 | "inputs":[ 288 | 289 | ], 290 | "name":"getCurrentBlockGasLimit", 291 | "outputs":[ 292 | { 293 | "internalType":"uint256", 294 | "name":"gaslimit", 295 | "type":"uint256" 296 | } 297 | ], 298 | "stateMutability":"view", 299 | "type":"function" 300 | }, 301 | { 302 | "inputs":[ 303 | 304 | ], 305 | "name":"getCurrentBlockTimestamp", 306 | "outputs":[ 307 | { 308 | "internalType":"uint256", 309 | "name":"timestamp", 310 | "type":"uint256" 311 | } 312 | ], 313 | "stateMutability":"view", 314 | "type":"function" 315 | }, 316 | { 317 | "inputs":[ 318 | { 319 | "internalType":"address", 320 | "name":"addr", 321 | "type":"address" 322 | } 323 | ], 324 | "name":"getEthBalance", 325 | "outputs":[ 326 | { 327 | "internalType":"uint256", 328 | "name":"balance", 329 | "type":"uint256" 330 | } 331 | ], 332 | "stateMutability":"view", 333 | "type":"function" 334 | }, 335 | { 336 | "inputs":[ 337 | 338 | ], 339 | "name":"getLastBlockHash", 340 | "outputs":[ 341 | { 342 | "internalType":"bytes32", 343 | "name":"blockHash", 344 | "type":"bytes32" 345 | } 346 | ], 347 | "stateMutability":"view", 348 | "type":"function" 349 | }, 350 | { 351 | "inputs":[ 352 | { 353 | "internalType":"bool", 354 | "name":"requireSuccess", 355 | "type":"bool" 356 | }, 357 | { 358 | "components":[ 359 | { 360 | "internalType":"address", 361 | "name":"target", 362 | "type":"address" 363 | }, 364 | { 365 | "internalType":"bytes", 366 | "name":"callData", 367 | "type":"bytes" 368 | } 369 | ], 370 | "internalType":"struct Multicall3.Call[]", 371 | "name":"calls", 372 | "type":"tuple[]" 373 | } 374 | ], 375 | "name":"tryAggregate", 376 | "outputs":[ 377 | { 378 | "components":[ 379 | { 380 | "internalType":"bool", 381 | "name":"success", 382 | "type":"bool" 383 | }, 384 | { 385 | "internalType":"bytes", 386 | "name":"returnData", 387 | "type":"bytes" 388 | } 389 | ], 390 | "internalType":"struct Multicall3.Result[]", 391 | "name":"returnData", 392 | "type":"tuple[]" 393 | } 394 | ], 395 | "stateMutability":"view", 396 | "type":"function" 397 | }, 398 | { 399 | "inputs":[ 400 | { 401 | "internalType":"bool", 402 | "name":"requireSuccess", 403 | "type":"bool" 404 | }, 405 | { 406 | "components":[ 407 | { 408 | "internalType":"address", 409 | "name":"target", 410 | "type":"address" 411 | }, 412 | { 413 | "internalType":"bytes", 414 | "name":"callData", 415 | "type":"bytes" 416 | } 417 | ], 418 | "internalType":"struct Multicall3.Call[]", 419 | "name":"calls", 420 | "type":"tuple[]" 421 | } 422 | ], 423 | "name":"tryBlockAndAggregate", 424 | "outputs":[ 425 | { 426 | "internalType":"uint256", 427 | "name":"blockNumber", 428 | "type":"uint256" 429 | }, 430 | { 431 | "internalType":"bytes32", 432 | "name":"blockHash", 433 | "type":"bytes32" 434 | }, 435 | { 436 | "components":[ 437 | { 438 | "internalType":"bool", 439 | "name":"success", 440 | "type":"bool" 441 | }, 442 | { 443 | "internalType":"bytes", 444 | "name":"returnData", 445 | "type":"bytes" 446 | } 447 | ], 448 | "internalType":"struct Multicall3.Result[]", 449 | "name":"returnData", 450 | "type":"tuple[]" 451 | } 452 | ], 453 | "stateMutability":"view", 454 | "type":"function" 455 | } 456 | ] -------------------------------------------------------------------------------- /contracts/contract_multicall/interface.go: -------------------------------------------------------------------------------- 1 | package contract_multicall 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 5 | ) 6 | 7 | // Interface is an abstraction of the contract. 8 | type Interface interface { 9 | Aggregate3(opts *bind.CallOpts, calls []Multicall3Call3) ([]Multicall3Result, error) 10 | } 11 | -------------------------------------------------------------------------------- /contracts/contract_multicall/multicall.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package contract_multicall 5 | 6 | import ( 7 | "errors" 8 | "math/big" 9 | "strings" 10 | 11 | ethereum "github.com/ethereum/go-ethereum" 12 | "github.com/ethereum/go-ethereum/accounts/abi" 13 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 14 | "github.com/ethereum/go-ethereum/common" 15 | "github.com/ethereum/go-ethereum/core/types" 16 | "github.com/ethereum/go-ethereum/event" 17 | ) 18 | 19 | // Reference imports to suppress errors if they are not otherwise used. 20 | var ( 21 | _ = errors.New 22 | _ = big.NewInt 23 | _ = strings.NewReader 24 | _ = ethereum.NotFound 25 | _ = bind.Bind 26 | _ = common.Big1 27 | _ = types.BloomLookup 28 | _ = event.NewSubscription 29 | _ = abi.ConvertType 30 | ) 31 | 32 | // Multicall3Call is an auto generated low-level Go binding around an user-defined struct. 33 | type Multicall3Call struct { 34 | Target common.Address 35 | CallData []byte 36 | } 37 | 38 | // Multicall3Call3 is an auto generated low-level Go binding around an user-defined struct. 39 | type Multicall3Call3 struct { 40 | Target common.Address 41 | AllowFailure bool 42 | CallData []byte 43 | } 44 | 45 | // Multicall3Call3Value is an auto generated low-level Go binding around an user-defined struct. 46 | type Multicall3Call3Value struct { 47 | Target common.Address 48 | AllowFailure bool 49 | Value *big.Int 50 | CallData []byte 51 | } 52 | 53 | // Multicall3Result is an auto generated low-level Go binding around an user-defined struct. 54 | type Multicall3Result struct { 55 | Success bool 56 | ReturnData []byte 57 | } 58 | 59 | // MulticallMetaData contains all meta data concerning the Multicall contract. 60 | var MulticallMetaData = &bind.MetaData{ 61 | ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", 62 | } 63 | 64 | // MulticallABI is the input ABI used to generate the binding from. 65 | // Deprecated: Use MulticallMetaData.ABI instead. 66 | var MulticallABI = MulticallMetaData.ABI 67 | 68 | // Multicall is an auto generated Go binding around an Ethereum contract. 69 | type Multicall struct { 70 | MulticallCaller // Read-only binding to the contract 71 | MulticallTransactor // Write-only binding to the contract 72 | MulticallFilterer // Log filterer for contract events 73 | } 74 | 75 | // MulticallCaller is an auto generated read-only Go binding around an Ethereum contract. 76 | type MulticallCaller struct { 77 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 78 | } 79 | 80 | // MulticallTransactor is an auto generated write-only Go binding around an Ethereum contract. 81 | type MulticallTransactor struct { 82 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 83 | } 84 | 85 | // MulticallFilterer is an auto generated log filtering Go binding around an Ethereum contract events. 86 | type MulticallFilterer struct { 87 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 88 | } 89 | 90 | // MulticallSession is an auto generated Go binding around an Ethereum contract, 91 | // with pre-set call and transact options. 92 | type MulticallSession struct { 93 | Contract *Multicall // Generic contract binding to set the session for 94 | CallOpts bind.CallOpts // Call options to use throughout this session 95 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 96 | } 97 | 98 | // MulticallCallerSession is an auto generated read-only Go binding around an Ethereum contract, 99 | // with pre-set call options. 100 | type MulticallCallerSession struct { 101 | Contract *MulticallCaller // Generic contract caller binding to set the session for 102 | CallOpts bind.CallOpts // Call options to use throughout this session 103 | } 104 | 105 | // MulticallTransactorSession is an auto generated write-only Go binding around an Ethereum contract, 106 | // with pre-set transact options. 107 | type MulticallTransactorSession struct { 108 | Contract *MulticallTransactor // Generic contract transactor binding to set the session for 109 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 110 | } 111 | 112 | // MulticallRaw is an auto generated low-level Go binding around an Ethereum contract. 113 | type MulticallRaw struct { 114 | Contract *Multicall // Generic contract binding to access the raw methods on 115 | } 116 | 117 | // MulticallCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. 118 | type MulticallCallerRaw struct { 119 | Contract *MulticallCaller // Generic read-only contract binding to access the raw methods on 120 | } 121 | 122 | // MulticallTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. 123 | type MulticallTransactorRaw struct { 124 | Contract *MulticallTransactor // Generic write-only contract binding to access the raw methods on 125 | } 126 | 127 | // NewMulticall creates a new instance of Multicall, bound to a specific deployed contract. 128 | func NewMulticall(address common.Address, backend bind.ContractBackend) (*Multicall, error) { 129 | contract, err := bindMulticall(address, backend, backend, backend) 130 | if err != nil { 131 | return nil, err 132 | } 133 | return &Multicall{MulticallCaller: MulticallCaller{contract: contract}, MulticallTransactor: MulticallTransactor{contract: contract}, MulticallFilterer: MulticallFilterer{contract: contract}}, nil 134 | } 135 | 136 | // NewMulticallCaller creates a new read-only instance of Multicall, bound to a specific deployed contract. 137 | func NewMulticallCaller(address common.Address, caller bind.ContractCaller) (*MulticallCaller, error) { 138 | contract, err := bindMulticall(address, caller, nil, nil) 139 | if err != nil { 140 | return nil, err 141 | } 142 | return &MulticallCaller{contract: contract}, nil 143 | } 144 | 145 | // NewMulticallTransactor creates a new write-only instance of Multicall, bound to a specific deployed contract. 146 | func NewMulticallTransactor(address common.Address, transactor bind.ContractTransactor) (*MulticallTransactor, error) { 147 | contract, err := bindMulticall(address, nil, transactor, nil) 148 | if err != nil { 149 | return nil, err 150 | } 151 | return &MulticallTransactor{contract: contract}, nil 152 | } 153 | 154 | // NewMulticallFilterer creates a new log filterer instance of Multicall, bound to a specific deployed contract. 155 | func NewMulticallFilterer(address common.Address, filterer bind.ContractFilterer) (*MulticallFilterer, error) { 156 | contract, err := bindMulticall(address, nil, nil, filterer) 157 | if err != nil { 158 | return nil, err 159 | } 160 | return &MulticallFilterer{contract: contract}, nil 161 | } 162 | 163 | // bindMulticall binds a generic wrapper to an already deployed contract. 164 | func bindMulticall(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 165 | parsed, err := MulticallMetaData.GetAbi() 166 | if err != nil { 167 | return nil, err 168 | } 169 | return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil 170 | } 171 | 172 | // Call invokes the (constant) contract method with params as input values and 173 | // sets the output to result. The result type might be a single field for simple 174 | // returns, a slice of interfaces for anonymous returns and a struct for named 175 | // returns. 176 | func (_Multicall *MulticallRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { 177 | return _Multicall.Contract.MulticallCaller.contract.Call(opts, result, method, params...) 178 | } 179 | 180 | // Transfer initiates a plain transaction to move funds to the contract, calling 181 | // its default method if one is available. 182 | func (_Multicall *MulticallRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 183 | return _Multicall.Contract.MulticallTransactor.contract.Transfer(opts) 184 | } 185 | 186 | // Transact invokes the (paid) contract method with params as input values. 187 | func (_Multicall *MulticallRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 188 | return _Multicall.Contract.MulticallTransactor.contract.Transact(opts, method, params...) 189 | } 190 | 191 | // Call invokes the (constant) contract method with params as input values and 192 | // sets the output to result. The result type might be a single field for simple 193 | // returns, a slice of interfaces for anonymous returns and a struct for named 194 | // returns. 195 | func (_Multicall *MulticallCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { 196 | return _Multicall.Contract.contract.Call(opts, result, method, params...) 197 | } 198 | 199 | // Transfer initiates a plain transaction to move funds to the contract, calling 200 | // its default method if one is available. 201 | func (_Multicall *MulticallTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 202 | return _Multicall.Contract.contract.Transfer(opts) 203 | } 204 | 205 | // Transact invokes the (paid) contract method with params as input values. 206 | func (_Multicall *MulticallTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 207 | return _Multicall.Contract.contract.Transact(opts, method, params...) 208 | } 209 | 210 | // Aggregate is a free data retrieval call binding the contract method 0x252dba42. 211 | // 212 | // Solidity: function aggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes[] returnData) 213 | func (_Multicall *MulticallCaller) Aggregate(opts *bind.CallOpts, calls []Multicall3Call) (struct { 214 | BlockNumber *big.Int 215 | ReturnData [][]byte 216 | }, error) { 217 | var out []interface{} 218 | err := _Multicall.contract.Call(opts, &out, "aggregate", calls) 219 | 220 | outstruct := new(struct { 221 | BlockNumber *big.Int 222 | ReturnData [][]byte 223 | }) 224 | if err != nil { 225 | return *outstruct, err 226 | } 227 | 228 | outstruct.BlockNumber = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 229 | outstruct.ReturnData = *abi.ConvertType(out[1], new([][]byte)).(*[][]byte) 230 | 231 | return *outstruct, err 232 | 233 | } 234 | 235 | // Aggregate is a free data retrieval call binding the contract method 0x252dba42. 236 | // 237 | // Solidity: function aggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes[] returnData) 238 | func (_Multicall *MulticallSession) Aggregate(calls []Multicall3Call) (struct { 239 | BlockNumber *big.Int 240 | ReturnData [][]byte 241 | }, error) { 242 | return _Multicall.Contract.Aggregate(&_Multicall.CallOpts, calls) 243 | } 244 | 245 | // Aggregate is a free data retrieval call binding the contract method 0x252dba42. 246 | // 247 | // Solidity: function aggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes[] returnData) 248 | func (_Multicall *MulticallCallerSession) Aggregate(calls []Multicall3Call) (struct { 249 | BlockNumber *big.Int 250 | ReturnData [][]byte 251 | }, error) { 252 | return _Multicall.Contract.Aggregate(&_Multicall.CallOpts, calls) 253 | } 254 | 255 | // Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb. 256 | // 257 | // Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData) 258 | func (_Multicall *MulticallCaller) Aggregate3(opts *bind.CallOpts, calls []Multicall3Call3) ([]Multicall3Result, error) { 259 | var out []interface{} 260 | err := _Multicall.contract.Call(opts, &out, "aggregate3", calls) 261 | 262 | if err != nil { 263 | return *new([]Multicall3Result), err 264 | } 265 | 266 | out0 := *abi.ConvertType(out[0], new([]Multicall3Result)).(*[]Multicall3Result) 267 | 268 | return out0, err 269 | 270 | } 271 | 272 | // Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb. 273 | // 274 | // Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData) 275 | func (_Multicall *MulticallSession) Aggregate3(calls []Multicall3Call3) ([]Multicall3Result, error) { 276 | return _Multicall.Contract.Aggregate3(&_Multicall.CallOpts, calls) 277 | } 278 | 279 | // Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb. 280 | // 281 | // Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData) 282 | func (_Multicall *MulticallCallerSession) Aggregate3(calls []Multicall3Call3) ([]Multicall3Result, error) { 283 | return _Multicall.Contract.Aggregate3(&_Multicall.CallOpts, calls) 284 | } 285 | 286 | // Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71. 287 | // 288 | // Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData) 289 | func (_Multicall *MulticallCaller) Aggregate3Value(opts *bind.CallOpts, calls []Multicall3Call3Value) ([]Multicall3Result, error) { 290 | var out []interface{} 291 | err := _Multicall.contract.Call(opts, &out, "aggregate3Value", calls) 292 | 293 | if err != nil { 294 | return *new([]Multicall3Result), err 295 | } 296 | 297 | out0 := *abi.ConvertType(out[0], new([]Multicall3Result)).(*[]Multicall3Result) 298 | 299 | return out0, err 300 | 301 | } 302 | 303 | // Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71. 304 | // 305 | // Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData) 306 | func (_Multicall *MulticallSession) Aggregate3Value(calls []Multicall3Call3Value) ([]Multicall3Result, error) { 307 | return _Multicall.Contract.Aggregate3Value(&_Multicall.CallOpts, calls) 308 | } 309 | 310 | // Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71. 311 | // 312 | // Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData) 313 | func (_Multicall *MulticallCallerSession) Aggregate3Value(calls []Multicall3Call3Value) ([]Multicall3Result, error) { 314 | return _Multicall.Contract.Aggregate3Value(&_Multicall.CallOpts, calls) 315 | } 316 | 317 | // BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9. 318 | // 319 | // Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) 320 | func (_Multicall *MulticallCaller) BlockAndAggregate(opts *bind.CallOpts, calls []Multicall3Call) (struct { 321 | BlockNumber *big.Int 322 | BlockHash [32]byte 323 | ReturnData []Multicall3Result 324 | }, error) { 325 | var out []interface{} 326 | err := _Multicall.contract.Call(opts, &out, "blockAndAggregate", calls) 327 | 328 | outstruct := new(struct { 329 | BlockNumber *big.Int 330 | BlockHash [32]byte 331 | ReturnData []Multicall3Result 332 | }) 333 | if err != nil { 334 | return *outstruct, err 335 | } 336 | 337 | outstruct.BlockNumber = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 338 | outstruct.BlockHash = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) 339 | outstruct.ReturnData = *abi.ConvertType(out[2], new([]Multicall3Result)).(*[]Multicall3Result) 340 | 341 | return *outstruct, err 342 | 343 | } 344 | 345 | // BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9. 346 | // 347 | // Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) 348 | func (_Multicall *MulticallSession) BlockAndAggregate(calls []Multicall3Call) (struct { 349 | BlockNumber *big.Int 350 | BlockHash [32]byte 351 | ReturnData []Multicall3Result 352 | }, error) { 353 | return _Multicall.Contract.BlockAndAggregate(&_Multicall.CallOpts, calls) 354 | } 355 | 356 | // BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9. 357 | // 358 | // Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) 359 | func (_Multicall *MulticallCallerSession) BlockAndAggregate(calls []Multicall3Call) (struct { 360 | BlockNumber *big.Int 361 | BlockHash [32]byte 362 | ReturnData []Multicall3Result 363 | }, error) { 364 | return _Multicall.Contract.BlockAndAggregate(&_Multicall.CallOpts, calls) 365 | } 366 | 367 | // GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. 368 | // 369 | // Solidity: function getBasefee() view returns(uint256 basefee) 370 | func (_Multicall *MulticallCaller) GetBasefee(opts *bind.CallOpts) (*big.Int, error) { 371 | var out []interface{} 372 | err := _Multicall.contract.Call(opts, &out, "getBasefee") 373 | 374 | if err != nil { 375 | return *new(*big.Int), err 376 | } 377 | 378 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 379 | 380 | return out0, err 381 | 382 | } 383 | 384 | // GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. 385 | // 386 | // Solidity: function getBasefee() view returns(uint256 basefee) 387 | func (_Multicall *MulticallSession) GetBasefee() (*big.Int, error) { 388 | return _Multicall.Contract.GetBasefee(&_Multicall.CallOpts) 389 | } 390 | 391 | // GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. 392 | // 393 | // Solidity: function getBasefee() view returns(uint256 basefee) 394 | func (_Multicall *MulticallCallerSession) GetBasefee() (*big.Int, error) { 395 | return _Multicall.Contract.GetBasefee(&_Multicall.CallOpts) 396 | } 397 | 398 | // GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. 399 | // 400 | // Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) 401 | func (_Multicall *MulticallCaller) GetBlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error) { 402 | var out []interface{} 403 | err := _Multicall.contract.Call(opts, &out, "getBlockHash", blockNumber) 404 | 405 | if err != nil { 406 | return *new([32]byte), err 407 | } 408 | 409 | out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) 410 | 411 | return out0, err 412 | 413 | } 414 | 415 | // GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. 416 | // 417 | // Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) 418 | func (_Multicall *MulticallSession) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { 419 | return _Multicall.Contract.GetBlockHash(&_Multicall.CallOpts, blockNumber) 420 | } 421 | 422 | // GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. 423 | // 424 | // Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) 425 | func (_Multicall *MulticallCallerSession) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { 426 | return _Multicall.Contract.GetBlockHash(&_Multicall.CallOpts, blockNumber) 427 | } 428 | 429 | // GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. 430 | // 431 | // Solidity: function getBlockNumber() view returns(uint256 blockNumber) 432 | func (_Multicall *MulticallCaller) GetBlockNumber(opts *bind.CallOpts) (*big.Int, error) { 433 | var out []interface{} 434 | err := _Multicall.contract.Call(opts, &out, "getBlockNumber") 435 | 436 | if err != nil { 437 | return *new(*big.Int), err 438 | } 439 | 440 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 441 | 442 | return out0, err 443 | 444 | } 445 | 446 | // GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. 447 | // 448 | // Solidity: function getBlockNumber() view returns(uint256 blockNumber) 449 | func (_Multicall *MulticallSession) GetBlockNumber() (*big.Int, error) { 450 | return _Multicall.Contract.GetBlockNumber(&_Multicall.CallOpts) 451 | } 452 | 453 | // GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. 454 | // 455 | // Solidity: function getBlockNumber() view returns(uint256 blockNumber) 456 | func (_Multicall *MulticallCallerSession) GetBlockNumber() (*big.Int, error) { 457 | return _Multicall.Contract.GetBlockNumber(&_Multicall.CallOpts) 458 | } 459 | 460 | // GetChainId is a free data retrieval call binding the contract method 0x3408e470. 461 | // 462 | // Solidity: function getChainId() view returns(uint256 chainid) 463 | func (_Multicall *MulticallCaller) GetChainId(opts *bind.CallOpts) (*big.Int, error) { 464 | var out []interface{} 465 | err := _Multicall.contract.Call(opts, &out, "getChainId") 466 | 467 | if err != nil { 468 | return *new(*big.Int), err 469 | } 470 | 471 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 472 | 473 | return out0, err 474 | 475 | } 476 | 477 | // GetChainId is a free data retrieval call binding the contract method 0x3408e470. 478 | // 479 | // Solidity: function getChainId() view returns(uint256 chainid) 480 | func (_Multicall *MulticallSession) GetChainId() (*big.Int, error) { 481 | return _Multicall.Contract.GetChainId(&_Multicall.CallOpts) 482 | } 483 | 484 | // GetChainId is a free data retrieval call binding the contract method 0x3408e470. 485 | // 486 | // Solidity: function getChainId() view returns(uint256 chainid) 487 | func (_Multicall *MulticallCallerSession) GetChainId() (*big.Int, error) { 488 | return _Multicall.Contract.GetChainId(&_Multicall.CallOpts) 489 | } 490 | 491 | // GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. 492 | // 493 | // Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) 494 | func (_Multicall *MulticallCaller) GetCurrentBlockCoinbase(opts *bind.CallOpts) (common.Address, error) { 495 | var out []interface{} 496 | err := _Multicall.contract.Call(opts, &out, "getCurrentBlockCoinbase") 497 | 498 | if err != nil { 499 | return *new(common.Address), err 500 | } 501 | 502 | out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) 503 | 504 | return out0, err 505 | 506 | } 507 | 508 | // GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. 509 | // 510 | // Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) 511 | func (_Multicall *MulticallSession) GetCurrentBlockCoinbase() (common.Address, error) { 512 | return _Multicall.Contract.GetCurrentBlockCoinbase(&_Multicall.CallOpts) 513 | } 514 | 515 | // GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. 516 | // 517 | // Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) 518 | func (_Multicall *MulticallCallerSession) GetCurrentBlockCoinbase() (common.Address, error) { 519 | return _Multicall.Contract.GetCurrentBlockCoinbase(&_Multicall.CallOpts) 520 | } 521 | 522 | // GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. 523 | // 524 | // Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) 525 | func (_Multicall *MulticallCaller) GetCurrentBlockDifficulty(opts *bind.CallOpts) (*big.Int, error) { 526 | var out []interface{} 527 | err := _Multicall.contract.Call(opts, &out, "getCurrentBlockDifficulty") 528 | 529 | if err != nil { 530 | return *new(*big.Int), err 531 | } 532 | 533 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 534 | 535 | return out0, err 536 | 537 | } 538 | 539 | // GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. 540 | // 541 | // Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) 542 | func (_Multicall *MulticallSession) GetCurrentBlockDifficulty() (*big.Int, error) { 543 | return _Multicall.Contract.GetCurrentBlockDifficulty(&_Multicall.CallOpts) 544 | } 545 | 546 | // GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. 547 | // 548 | // Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) 549 | func (_Multicall *MulticallCallerSession) GetCurrentBlockDifficulty() (*big.Int, error) { 550 | return _Multicall.Contract.GetCurrentBlockDifficulty(&_Multicall.CallOpts) 551 | } 552 | 553 | // GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. 554 | // 555 | // Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) 556 | func (_Multicall *MulticallCaller) GetCurrentBlockGasLimit(opts *bind.CallOpts) (*big.Int, error) { 557 | var out []interface{} 558 | err := _Multicall.contract.Call(opts, &out, "getCurrentBlockGasLimit") 559 | 560 | if err != nil { 561 | return *new(*big.Int), err 562 | } 563 | 564 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 565 | 566 | return out0, err 567 | 568 | } 569 | 570 | // GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. 571 | // 572 | // Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) 573 | func (_Multicall *MulticallSession) GetCurrentBlockGasLimit() (*big.Int, error) { 574 | return _Multicall.Contract.GetCurrentBlockGasLimit(&_Multicall.CallOpts) 575 | } 576 | 577 | // GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. 578 | // 579 | // Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) 580 | func (_Multicall *MulticallCallerSession) GetCurrentBlockGasLimit() (*big.Int, error) { 581 | return _Multicall.Contract.GetCurrentBlockGasLimit(&_Multicall.CallOpts) 582 | } 583 | 584 | // GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. 585 | // 586 | // Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) 587 | func (_Multicall *MulticallCaller) GetCurrentBlockTimestamp(opts *bind.CallOpts) (*big.Int, error) { 588 | var out []interface{} 589 | err := _Multicall.contract.Call(opts, &out, "getCurrentBlockTimestamp") 590 | 591 | if err != nil { 592 | return *new(*big.Int), err 593 | } 594 | 595 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 596 | 597 | return out0, err 598 | 599 | } 600 | 601 | // GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. 602 | // 603 | // Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) 604 | func (_Multicall *MulticallSession) GetCurrentBlockTimestamp() (*big.Int, error) { 605 | return _Multicall.Contract.GetCurrentBlockTimestamp(&_Multicall.CallOpts) 606 | } 607 | 608 | // GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. 609 | // 610 | // Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) 611 | func (_Multicall *MulticallCallerSession) GetCurrentBlockTimestamp() (*big.Int, error) { 612 | return _Multicall.Contract.GetCurrentBlockTimestamp(&_Multicall.CallOpts) 613 | } 614 | 615 | // GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. 616 | // 617 | // Solidity: function getEthBalance(address addr) view returns(uint256 balance) 618 | func (_Multicall *MulticallCaller) GetEthBalance(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { 619 | var out []interface{} 620 | err := _Multicall.contract.Call(opts, &out, "getEthBalance", addr) 621 | 622 | if err != nil { 623 | return *new(*big.Int), err 624 | } 625 | 626 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 627 | 628 | return out0, err 629 | 630 | } 631 | 632 | // GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. 633 | // 634 | // Solidity: function getEthBalance(address addr) view returns(uint256 balance) 635 | func (_Multicall *MulticallSession) GetEthBalance(addr common.Address) (*big.Int, error) { 636 | return _Multicall.Contract.GetEthBalance(&_Multicall.CallOpts, addr) 637 | } 638 | 639 | // GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. 640 | // 641 | // Solidity: function getEthBalance(address addr) view returns(uint256 balance) 642 | func (_Multicall *MulticallCallerSession) GetEthBalance(addr common.Address) (*big.Int, error) { 643 | return _Multicall.Contract.GetEthBalance(&_Multicall.CallOpts, addr) 644 | } 645 | 646 | // GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. 647 | // 648 | // Solidity: function getLastBlockHash() view returns(bytes32 blockHash) 649 | func (_Multicall *MulticallCaller) GetLastBlockHash(opts *bind.CallOpts) ([32]byte, error) { 650 | var out []interface{} 651 | err := _Multicall.contract.Call(opts, &out, "getLastBlockHash") 652 | 653 | if err != nil { 654 | return *new([32]byte), err 655 | } 656 | 657 | out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) 658 | 659 | return out0, err 660 | 661 | } 662 | 663 | // GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. 664 | // 665 | // Solidity: function getLastBlockHash() view returns(bytes32 blockHash) 666 | func (_Multicall *MulticallSession) GetLastBlockHash() ([32]byte, error) { 667 | return _Multicall.Contract.GetLastBlockHash(&_Multicall.CallOpts) 668 | } 669 | 670 | // GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. 671 | // 672 | // Solidity: function getLastBlockHash() view returns(bytes32 blockHash) 673 | func (_Multicall *MulticallCallerSession) GetLastBlockHash() ([32]byte, error) { 674 | return _Multicall.Contract.GetLastBlockHash(&_Multicall.CallOpts) 675 | } 676 | 677 | // TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7. 678 | // 679 | // Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData) 680 | func (_Multicall *MulticallCaller) TryAggregate(opts *bind.CallOpts, requireSuccess bool, calls []Multicall3Call) ([]Multicall3Result, error) { 681 | var out []interface{} 682 | err := _Multicall.contract.Call(opts, &out, "tryAggregate", requireSuccess, calls) 683 | 684 | if err != nil { 685 | return *new([]Multicall3Result), err 686 | } 687 | 688 | out0 := *abi.ConvertType(out[0], new([]Multicall3Result)).(*[]Multicall3Result) 689 | 690 | return out0, err 691 | 692 | } 693 | 694 | // TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7. 695 | // 696 | // Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData) 697 | func (_Multicall *MulticallSession) TryAggregate(requireSuccess bool, calls []Multicall3Call) ([]Multicall3Result, error) { 698 | return _Multicall.Contract.TryAggregate(&_Multicall.CallOpts, requireSuccess, calls) 699 | } 700 | 701 | // TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7. 702 | // 703 | // Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData) 704 | func (_Multicall *MulticallCallerSession) TryAggregate(requireSuccess bool, calls []Multicall3Call) ([]Multicall3Result, error) { 705 | return _Multicall.Contract.TryAggregate(&_Multicall.CallOpts, requireSuccess, calls) 706 | } 707 | 708 | // TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9. 709 | // 710 | // Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) 711 | func (_Multicall *MulticallCaller) TryBlockAndAggregate(opts *bind.CallOpts, requireSuccess bool, calls []Multicall3Call) (struct { 712 | BlockNumber *big.Int 713 | BlockHash [32]byte 714 | ReturnData []Multicall3Result 715 | }, error) { 716 | var out []interface{} 717 | err := _Multicall.contract.Call(opts, &out, "tryBlockAndAggregate", requireSuccess, calls) 718 | 719 | outstruct := new(struct { 720 | BlockNumber *big.Int 721 | BlockHash [32]byte 722 | ReturnData []Multicall3Result 723 | }) 724 | if err != nil { 725 | return *outstruct, err 726 | } 727 | 728 | outstruct.BlockNumber = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 729 | outstruct.BlockHash = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) 730 | outstruct.ReturnData = *abi.ConvertType(out[2], new([]Multicall3Result)).(*[]Multicall3Result) 731 | 732 | return *outstruct, err 733 | 734 | } 735 | 736 | // TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9. 737 | // 738 | // Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) 739 | func (_Multicall *MulticallSession) TryBlockAndAggregate(requireSuccess bool, calls []Multicall3Call) (struct { 740 | BlockNumber *big.Int 741 | BlockHash [32]byte 742 | ReturnData []Multicall3Result 743 | }, error) { 744 | return _Multicall.Contract.TryBlockAndAggregate(&_Multicall.CallOpts, requireSuccess, calls) 745 | } 746 | 747 | // TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9. 748 | // 749 | // Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) 750 | func (_Multicall *MulticallCallerSession) TryBlockAndAggregate(requireSuccess bool, calls []Multicall3Call) (struct { 751 | BlockNumber *big.Int 752 | BlockHash [32]byte 753 | ReturnData []Multicall3Result 754 | }, error) { 755 | return _Multicall.Contract.TryBlockAndAggregate(&_Multicall.CallOpts, requireSuccess, calls) 756 | } 757 | -------------------------------------------------------------------------------- /examples/agent_registry/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/forta-network/go-multicall" 11 | ) 12 | 13 | const ( 14 | APIURL = "https://polygon-rpc.com" 15 | AgentRegistryABI = `[ 16 | { 17 | "inputs":[ 18 | { 19 | "internalType":"uint256", 20 | "name":"agentId", 21 | "type":"uint256" 22 | } 23 | ], 24 | "name":"getAgentState", 25 | "outputs":[ 26 | { 27 | "internalType":"bool", 28 | "name":"registered", 29 | "type":"bool" 30 | }, 31 | { 32 | "internalType":"address", 33 | "name":"owner", 34 | "type":"address" 35 | }, 36 | { 37 | "internalType":"uint256", 38 | "name":"agentVersion", 39 | "type":"uint256" 40 | }, 41 | { 42 | "internalType":"string", 43 | "name":"metadata", 44 | "type":"string" 45 | }, 46 | { 47 | "internalType":"uint256[]", 48 | "name":"chainIds", 49 | "type":"uint256[]" 50 | }, 51 | { 52 | "internalType":"bool", 53 | "name":"enabled", 54 | "type":"bool" 55 | }, 56 | { 57 | "internalType":"uint256", 58 | "name":"disabledFlags", 59 | "type":"uint256" 60 | } 61 | ], 62 | "stateMutability":"view", 63 | "type":"function" 64 | } 65 | ]` 66 | ) 67 | 68 | type agentState struct { 69 | Registered bool 70 | Owner common.Address 71 | AgentVersion *big.Int 72 | Metadata string 73 | ChainIds []*big.Int 74 | Enabled bool 75 | DisabledFlags *big.Int 76 | } 77 | 78 | func main() { 79 | caller, err := multicall.Dial(context.Background(), APIURL) 80 | if err != nil { 81 | panic(err) 82 | } 83 | 84 | // Forta AgentRegistry 85 | agentReg, err := multicall.NewContract(AgentRegistryABI, "0x61447385B019187daa48e91c55c02AF1F1f3F863") 86 | if err != nil { 87 | panic(err) 88 | } 89 | 90 | calls, err := caller.Call(nil, 91 | agentReg.NewCall( 92 | new(agentState), 93 | "getAgentState", 94 | botHexToBigInt("0x80ed808b586aeebe9cdd4088ea4dea0a8e322909c0e4493c993e060e89c09ed1"), 95 | ), 96 | ) 97 | if err != nil { 98 | panic(err) 99 | } 100 | fmt.Println("owner:", calls[0].Outputs.(*agentState).Owner.String()) 101 | 102 | b, _ := json.MarshalIndent(calls[0].Outputs.(*agentState), "", " ") 103 | fmt.Println(string(b)) 104 | } 105 | 106 | func botHexToBigInt(hex string) *big.Int { 107 | return common.HexToHash(hex).Big() 108 | } 109 | -------------------------------------------------------------------------------- /examples/balance/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math/big" 7 | 8 | "github.com/ethereum/go-ethereum/common" 9 | "github.com/forta-network/go-multicall" 10 | ) 11 | 12 | const ( 13 | APIURL = "https://cloudflare-eth.com" 14 | ERC20ABI = `[ 15 | { 16 | "constant":true, 17 | "inputs":[ 18 | { 19 | "name":"tokenOwner", 20 | "type":"address" 21 | } 22 | ], 23 | "name":"balanceOf", 24 | "outputs":[ 25 | { 26 | "name":"balance", 27 | "type":"uint256" 28 | } 29 | ], 30 | "payable":false, 31 | "stateMutability":"view", 32 | "type":"function" 33 | } 34 | ]` 35 | ) 36 | 37 | type balanceOutput struct { 38 | Balance *big.Int 39 | } 40 | 41 | func main() { 42 | caller, err := multicall.Dial(context.Background(), APIURL) 43 | if err != nil { 44 | panic(err) 45 | } 46 | 47 | contract, err := multicall.NewContract(ERC20ABI, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") 48 | if err != nil { 49 | panic(err) 50 | } 51 | 52 | calls, err := caller.Call(nil, 53 | contract.NewCall( 54 | new(balanceOutput), 55 | "balanceOf", 56 | common.HexToAddress("0xcEe284F754E854890e311e3280b767F80797180d"), // Arbitrum One gateway 57 | ).Name("Arbitrum One gateway balance"), 58 | contract.NewCall( 59 | new(balanceOutput), 60 | "balanceOf", 61 | common.HexToAddress("0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf"), // Polygon ERC20 bridge 62 | ).Name("Polygon ERC20 bridge balance"), 63 | ) 64 | if err != nil { 65 | panic(err) 66 | } 67 | for _, call := range calls { 68 | fmt.Println(call.CallName, ":", call.Outputs.(*balanceOutput).Balance) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/forta-network/go-multicall 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/ethereum/go-ethereum v1.11.5 7 | github.com/stretchr/testify v1.8.2 8 | ) 9 | 10 | require ( 11 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect 12 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/deckarep/golang-set/v2 v2.1.0 // indirect 15 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 16 | github.com/fsnotify/fsnotify v1.6.0 // indirect 17 | github.com/go-ole/go-ole v1.2.1 // indirect 18 | github.com/go-stack/stack v1.8.1 // indirect 19 | github.com/google/uuid v1.3.0 // indirect 20 | github.com/gorilla/websocket v1.4.2 // indirect 21 | github.com/holiman/uint256 v1.2.0 // indirect 22 | github.com/pmezard/go-difflib v1.0.0 // indirect 23 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect 24 | github.com/tklauser/go-sysconf v0.3.5 // indirect 25 | github.com/tklauser/numcpus v0.2.2 // indirect 26 | golang.org/x/crypto v0.1.0 // indirect 27 | golang.org/x/sys v0.5.0 // indirect 28 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect 29 | gopkg.in/yaml.v3 v3.0.1 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= 2 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= 3 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 4 | github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= 5 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 6 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= 7 | github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= 8 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= 9 | github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= 10 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 11 | github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= 12 | github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= 13 | github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= 14 | github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= 15 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= 16 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 18 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 19 | github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= 20 | github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= 21 | github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= 22 | github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= 23 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= 24 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= 25 | github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= 26 | github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= 27 | github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= 28 | github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= 29 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 30 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 31 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= 32 | github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= 33 | github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= 34 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= 35 | github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= 36 | github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= 37 | github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= 38 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 39 | github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= 40 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 41 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 42 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 43 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 44 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 45 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 46 | github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= 47 | github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= 48 | github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= 49 | github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= 50 | github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= 51 | github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= 52 | github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= 53 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 54 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 55 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 56 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 57 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 58 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 59 | github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= 60 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 61 | github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= 62 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 63 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 64 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 65 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 66 | github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= 67 | github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= 68 | github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= 69 | github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= 70 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 71 | github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= 72 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 73 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= 74 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 75 | github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= 76 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 77 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 78 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 79 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 80 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 81 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 82 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 83 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= 84 | github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= 85 | github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= 86 | github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= 87 | github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= 88 | github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= 89 | github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= 90 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= 91 | golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= 92 | golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 93 | golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= 94 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 95 | golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 96 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 97 | golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= 98 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 99 | golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= 100 | golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= 101 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 102 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 103 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 104 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= 105 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= 106 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 107 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 108 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 109 | --------------------------------------------------------------------------------