diff --git a/abi.go b/abi.go new file mode 100644 index 0000000..4188e4b --- /dev/null +++ b/abi.go @@ -0,0 +1,49 @@ +package celoutils + +import ( + "io" + + "github.com/celo-org/celo-blockchain/accounts/abi" +) + +type ( + ParsedABI struct { + EventSignatures []EventSignature + MethodSignatures []MethodSignature + } +) + +func ParseABI(abiReader io.Reader) (*ParsedABI, error) { + abi, err := abi.JSON(abiReader) + if err != nil { + return nil, err + } + + var ( + eventSignatures []EventSignature + methodsSignatures []MethodSignature + ) + + for _, v := range abi.Events { + eventSignature, err := EventSignatureFromString(v.Sig) + if err != nil { + return nil, err + } + + eventSignatures = append(eventSignatures, eventSignature) + } + + for _, v := range abi.Methods { + methodSignature, err := MethodSignatureFromString(v.Sig) + if err != nil { + return nil, err + } + + methodsSignatures = append(methodsSignatures, methodSignature) + } + + return &ParsedABI{ + EventSignatures: eventSignatures, + MethodSignatures: methodsSignatures, + }, nil +} diff --git a/abi_test.go b/abi_test.go new file mode 100644 index 0000000..704b252 --- /dev/null +++ b/abi_test.go @@ -0,0 +1,57 @@ +package celoutils + +import ( + "reflect" + "strings" + "testing" +) + +func TestParseABI(t *testing.T) { + // contract T { + // event received(address sender, uint amount, bytes memo); + // event receivedAddr(address sender); + // function receive(bytes memo) external payable { + // received(msg.sender, msg.value, memo); + // receivedAddr(msg.sender); + // } + // } + // https://www.4byte.directory/event-signatures + // 253837 received(address,uint256,bytes) 0x75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed + // 253838 receivedAddr(address) 0x46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c8 + eventSignatures := []EventSignature{ + { + Signature: "received(address,uint256,bytes)", + Hash: "0x75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed", + }, + { + Signature: "receivedAddr(address)", + Hash: "0x46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c8", + }, + } + + methodSignatures := []MethodSignature{ + { + Signature: "receive(bytes)", + Hash: "a69b6ed0", + }, + } + + want := &ParsedABI{ + EventSignatures: eventSignatures, + MethodSignatures: methodSignatures, + } + + json := `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` + got, err := ParseABI(strings.NewReader(json)) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(got.EventSignatures, want.EventSignatures) { + t.Errorf("Event signatures slices should be equal, got %v and %v", got, want) + } + + if !reflect.DeepEqual(got.MethodSignatures, want.MethodSignatures) { + t.Errorf("Method signatures slices should be equal, got %v and %v", got, want) + } +} diff --git a/event.go b/event.go index df1a58b..c9eb471 100644 --- a/event.go +++ b/event.go @@ -1,10 +1,8 @@ package celoutils import ( - "io" "strings" - "github.com/celo-org/celo-blockchain/accounts/abi" "github.com/grassrootseconomics/w3-celo" ) @@ -15,7 +13,7 @@ type ( } ) -func EventSignatureHash(eventSignature string) (EventSignature, error) { +func EventSignatureFromString(eventSignature string) (EventSignature, error) { event, err := w3.NewEvent(strings.TrimSuffix(eventSignature, ";")) if err != nil { return EventSignature{}, err @@ -26,23 +24,3 @@ func EventSignatureHash(eventSignature string) (EventSignature, error) { Hash: event.Topic0.Hex(), }, nil } - -func EventSignatureHashesFromABI(abiReader io.Reader) ([]EventSignature, error) { - abi, err := abi.JSON(abiReader) - if err != nil { - return nil, err - } - - var eventSignatures []EventSignature - - for _, v := range abi.Events { - eventSignatureHash, err := EventSignatureHash(v.Sig) - if err != nil { - return nil, err - } - - eventSignatures = append(eventSignatures, eventSignatureHash) - } - - return eventSignatures, nil -} diff --git a/event_test.go b/event_test.go index f6497c7..1570c71 100644 --- a/event_test.go +++ b/event_test.go @@ -1,8 +1,6 @@ package celoutils import ( - "reflect" - "strings" "testing" ) @@ -38,7 +36,7 @@ func TestEventSignatureHash(t *testing.T) { { name: "Transfer Event variant 3", args: args{ - event: "Transfer(address indexed _from, address indexed _to, uint256 _value)", + event: "Transfer(address indexed _from, address indexed _to, uint256 _value);", }, want: EventSignature{ Signature: "Transfer(address,address,uint256)", @@ -48,7 +46,7 @@ func TestEventSignatureHash(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := EventSignatureHash(tt.args.event) + got, err := EventSignatureFromString(tt.args.event) if err != nil { t.Errorf("EventSignatureHash() got error: %v", err) } @@ -58,37 +56,3 @@ func TestEventSignatureHash(t *testing.T) { }) } } - -func TestEventSignatureHashesFromABI(t *testing.T) { - // contract T { - // event received(address sender, uint amount, bytes memo); - // event receivedAddr(address sender); - // function receive(bytes memo) external payable { - // received(msg.sender, msg.value, memo); - // receivedAddr(msg.sender); - // } - // } - // https://www.4byte.directory/event-signatures - // 253837 received(address,uint256,bytes) 0x75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed - // 253838 receivedAddr(address) 0x46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c8 - want := []EventSignature{ - { - Signature: "received(address,uint256,bytes)", - Hash: "0x75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed", - }, - { - Signature: "receivedAddr(address)", - Hash: "0x46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c8", - }, - } - - json := `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` - got, err := EventSignatureHashesFromABI(strings.NewReader(json)) - if err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Slices should be equal, got %v and %v", got, want) - } -} diff --git a/method.go b/method.go new file mode 100644 index 0000000..f7004a4 --- /dev/null +++ b/method.go @@ -0,0 +1,26 @@ +package celoutils + +import ( + "encoding/hex" + + "github.com/grassrootseconomics/w3-celo" +) + +type ( + MethodSignature struct { + Signature string + Hash string + } +) + +func MethodSignatureFromString(methodSignature string) (MethodSignature, error) { + method, err := w3.NewFunc(methodSignature, "") + if err != nil { + return MethodSignature{}, err + } + + return MethodSignature{ + Signature: method.Signature, + Hash: hex.EncodeToString(method.Selector[:]), + }, nil +} diff --git a/method_test.go b/method_test.go new file mode 100644 index 0000000..e44341d --- /dev/null +++ b/method_test.go @@ -0,0 +1,41 @@ +package celoutils + +import ( + "reflect" + "testing" +) + +func TestMethodSignatureFromString(t *testing.T) { + type args struct { + methodSignature string + } + tests := []struct { + name string + args args + want MethodSignature + wantErr bool + }{ + { + name: "Transfer Method", + args: args{ + methodSignature: "transfer(address, uint256)", + }, + want: MethodSignature{ + Signature: "transfer(address,uint256)", + Hash: "a9059cbb", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := MethodSignatureFromString(tt.args.methodSignature) + if (err != nil) != tt.wantErr { + t.Errorf("MethodSignatureFromString() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("MethodSignatureFromString() = %v, want %v", got, tt.want) + } + }) + } +}