github.com/lmittmann/w3@v0.20.0/internal/abi/arguments.go (about) 1 package abi 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/ethereum/go-ethereum/accounts/abi" 9 "github.com/lmittmann/w3/internal/crypto" 10 ) 11 12 // Arguments represents a slice of [abi.Argument]'s. 13 type Arguments []abi.Argument 14 15 func (a Arguments) Signature() string { 16 if len(a) <= 0 { 17 return "" 18 } 19 20 fields := make([]string, len(a)) 21 for i, arg := range a { 22 fields[i] = typeToString(&arg.Type) 23 } 24 return strings.Join(fields, ",") 25 } 26 27 func (a Arguments) SignatureWithName(name string) string { 28 return name + "(" + a.Signature() + ")" 29 } 30 31 // Encode ABI-encodes the given arguments args. 32 func (a Arguments) Encode(args ...any) ([]byte, error) { 33 data, err := abi.Arguments(a).PackValues(args) 34 if err != nil { 35 return nil, err 36 } 37 return data, nil 38 } 39 40 // EncodeWithSelector ABI-encodes the given arguments args prepended by the 41 // given selector. 42 func (a Arguments) EncodeWithSelector(selector [4]byte, args ...any) ([]byte, error) { 43 data, err := a.Encode(args...) 44 if err != nil { 45 return nil, err 46 } 47 48 data = append(selector[:], data...) 49 return data, nil 50 } 51 52 // EncodeWithSignature ABI-encodes the given arguments args prepended by the 53 // first 4 bytes of the hash of the given signature. 54 func (a Arguments) EncodeWithSignature(signature string, args ...any) ([]byte, error) { 55 var selector [4]byte 56 copy(selector[:], crypto.Keccak256([]byte(signature))[:4]) 57 58 return a.EncodeWithSelector(selector, args...) 59 } 60 61 // Decode ABI-decodes the given data to the given arguments args. 62 func (a Arguments) Decode(data []byte, args ...any) error { 63 values, err := abi.Arguments(a).UnpackValues(data) 64 if err != nil { 65 return err 66 } 67 68 for i, arg := range args { 69 // discard if arg is nil 70 if arg == nil { 71 continue 72 } 73 74 if err := Copy(arg, values[i]); err != nil { 75 return err 76 } 77 } 78 return nil 79 } 80 81 // typeToString returns the string representation of a [abi.Type]. 82 func typeToString(t *abi.Type) string { 83 switch t.T { 84 case abi.IntTy: 85 return "int" + strconv.Itoa(t.Size) 86 case abi.UintTy: 87 return "uint" + strconv.Itoa(t.Size) 88 case abi.BoolTy: 89 return "bool" 90 case abi.StringTy: 91 return "string" 92 case abi.SliceTy: 93 return typeToString(t.Elem) + "[]" 94 case abi.ArrayTy: 95 return typeToString(t.Elem) + "[" + strconv.Itoa(t.Size) + "]" 96 case abi.TupleTy: 97 fields := make([]string, len(t.TupleElems)) 98 for i, elem := range t.TupleElems { 99 fields[i] = typeToString(elem) 100 } 101 return "(" + strings.Join(fields, ",") + ")" 102 case abi.AddressTy: 103 return "address" 104 case abi.FixedBytesTy: 105 return "bytes" + strconv.Itoa(t.Size) 106 case abi.BytesTy: 107 return "bytes" 108 case abi.HashTy: 109 return "hash" 110 default: 111 panic(fmt.Sprintf("unsupported type %v", t)) 112 } 113 }