From c6cbb984a3244179bc0255a3ac71f2e7a1426e3a Mon Sep 17 00:00:00 2001 From: cary Date: Sat, 18 Apr 2026 16:32:52 +0800 Subject: [PATCH] fix: multiple bug fixes and safety improvements - call.go: safe type assertion in UnpackResult() to prevent panic - call.go: warn when ABI returns more values than struct fields - caller.go: use len() check instead of nil check for variadic multicallAddr - caller.go: return allCalls (partial results) on CallChunked error - caller_test.go: strip 4-byte method selector from stub return data Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- call.go | 10 +++++++++- caller.go | 4 ++-- caller_test.go | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/call.go b/call.go index 6fa5567..05c06ab 100644 --- a/call.go +++ b/call.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "log" "reflect" "github.com/ethereum/go-ethereum/accounts/abi" @@ -77,7 +78,11 @@ func (call *Call) UnpackResult() []interface{} { if call.Outputs == nil { return nil } - return call.Outputs.([]interface{}) + result, ok := call.Outputs.([]interface{}) + if !ok { + return nil + } + return result } // AllowFailure sets if the call is allowed to fail. This helps avoiding a revert @@ -111,6 +116,9 @@ func (call *Call) Unpack(b []byte) error { if fieldCount > len(out) { return fmt.Errorf("struct has %d fields but ABI returned %d values", fieldCount, len(out)) } + if len(out) > fieldCount { + log.Printf("warning: method '%s' returned %d values but struct only has %d fields; extra values ignored", call.Method, len(out), fieldCount) + } for i := 0; i < fieldCount; i++ { field := t.Field(i) if !field.CanSet() { diff --git a/caller.go b/caller.go index 96e4d64..bba1753 100644 --- a/caller.go +++ b/caller.go @@ -24,7 +24,7 @@ type Caller struct { // New creates a new caller. func New(client bind.ContractCaller, multicallAddr ...string) (*Caller, error) { addr := DefaultAddress - if multicallAddr != nil { + if len(multicallAddr) > 0 { addr = multicallAddr[0] } contract, err := contract_multicall.NewMulticallCaller(common.HexToAddress(addr), client) @@ -107,7 +107,7 @@ func (caller *Caller) CallChunked(opts *bind.CallOpts, chunkSize int, cooldown t chunk, err := caller.calls(opts, chunk...) if err != nil { - return calls, fmt.Errorf("call chunk [%d] failed: %v", i, err) + return allCalls, fmt.Errorf("call chunk [%d] failed: %v", i, err) } allCalls = append(allCalls, chunk...) } diff --git a/caller_test.go b/caller_test.go index 54e3068..5a7ef33 100644 --- a/caller_test.go +++ b/caller_test.go @@ -306,7 +306,7 @@ func TestCaller_WrongOutputsType(t *testing.T) { contract: &multicallStub{ returnData: func(calls []contract_multicall.Multicall3Call3) [][]byte { return [][]byte{ - packedOutput, + packedOutput[4:], // strip 4-byte method selector; return data is ABI-encoded outputs only } }, },