diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 62b860e18c..55576070a4 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -222,6 +222,17 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) } +// ErrorByID looks up an error by the 4-byte id, +// returns nil if none found. +func (abi *ABI) ErrorByID(sigdata [4]byte) (*Error, error) { + for _, errABI := range abi.Errors { + if bytes.Equal(errABI.ID[:4], sigdata[:]) { + return &errABI, nil + } + } + return nil, fmt.Errorf("no error with id: %#x", sigdata[:]) +} + // HasFallback returns an indicator whether a fallback function is included. func (abi *ABI) HasFallback() bool { return abi.Fallback.Type == Fallback diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 96c11e0964..3486ffd1a5 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1057,6 +1057,34 @@ func TestABI_EventById(t *testing.T) { } } +func TestABI_ErrorByID(t *testing.T) { + abi, err := JSON(strings.NewReader(`[ + {"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"}, + {"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"}, + {"inputs":[{"internalType":"uint256[]","name":"x","type":"uint256[]"}],"name":"MyError3","type":"error"} + ]`)) + if err != nil { + t.Fatal(err) + } + for name, m := range abi.Errors { + a := fmt.Sprintf("%v", &m) + var id [4]byte + copy(id[:], m.ID[:4]) + m2, err := abi.ErrorByID(id) + if err != nil { + t.Fatalf("Failed to look up ABI error: %v", err) + } + b := fmt.Sprintf("%v", m2) + if a != b { + t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, id) + } + } + // test unsuccessful lookups + if _, err = abi.ErrorByID([4]byte{}); err == nil { + t.Error("Expected error: no error with this id") + } +} + // TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name // conflict and that the second transfer method will be renamed transfer1. func TestDoubleDuplicateMethodNames(t *testing.T) { diff --git a/accounts/abi/error.go b/accounts/abi/error.go index f53c996def..f65f0d2cc2 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -78,7 +78,7 @@ func NewError(name string, inputs Arguments) Error { } } -func (e *Error) String() string { +func (e Error) String() string { return e.str }