github.com/lmittmann/w3@v0.20.0/internal/abi/tuple.go (about) 1 package abi 2 3 import ( 4 "errors" 5 "fmt" 6 "math/big" 7 "reflect" 8 "unicode" 9 10 "github.com/ethereum/go-ethereum/accounts/abi" 11 "github.com/ethereum/go-ethereum/common" 12 ) 13 14 var errDuplicateTuple = errors.New("duplicate tuple definition") 15 16 func tupleMap(tuples ...any) (map[string]reflect.Type, error) { 17 types := make(map[string]reflect.Type) 18 for _, t := range tuples { 19 typ := reflect.TypeOf(t) 20 if typ.Kind() != reflect.Struct { 21 return nil, fmt.Errorf("expected struct, got %s", typ.Kind()) 22 } 23 24 if _, ok := types[typ.Name()]; ok { 25 return nil, fmt.Errorf("%w: %s", errDuplicateTuple, typ.Name()) 26 } 27 types[typ.Name()] = typ 28 } 29 return types, nil 30 } 31 32 func buildTuples(tuples ...any) (map[string]abi.Argument, error) { 33 types := make(map[string]abi.Argument) 34 for _, t := range tuples { 35 typ := reflect.TypeOf(t) 36 if typ.Kind() != reflect.Struct { 37 return nil, fmt.Errorf("expected struct, got %s", typ.Kind()) 38 } 39 40 if _, ok := types[typ.Name()]; ok { 41 return nil, fmt.Errorf("%w: %s", errDuplicateTuple, typ.Name()) 42 } 43 44 abiTyp, err := typeOf(typ, "") 45 if err != nil { 46 return nil, err 47 } 48 49 arg := abi.Argument{ 50 Name: typ.Name(), 51 Type: *abiTyp, 52 } 53 types[typ.Name()] = arg 54 } 55 return types, nil 56 } 57 58 // typeOfField returns the [abi.Type] of a struct field. 59 func typeOfField(field reflect.StructField) (*abi.Type, error) { 60 const tagKey = "abitype" 61 62 tag, _ := field.Tag.Lookup(tagKey) 63 return typeOf(field.Type, tag) // tag is "" if not set 64 } 65 66 func typeOf(typ reflect.Type, abiType string) (*abi.Type, error) { 67 abiT, isBasicT := basicTypes[typ] 68 if !isBasicT { 69 switch typ.Kind() { 70 case reflect.Slice: 71 elemAibT, err := typeOf(typ.Elem(), abiType) 72 if err != nil { 73 return nil, err 74 } 75 return &abi.Type{ 76 T: abi.SliceTy, 77 Elem: elemAibT, 78 }, nil 79 case reflect.Array: 80 elemAibT, err := typeOf(typ.Elem(), abiType) 81 if err != nil { 82 return nil, err 83 } 84 return &abi.Type{ 85 T: abi.ArrayTy, 86 Elem: elemAibT, 87 Size: typ.Len(), 88 }, nil 89 case reflect.Struct: 90 num := typ.NumField() 91 elems := make([]*abi.Type, num) 92 rawNames := make([]string, num) 93 for i := range num { 94 f := typ.Field(i) 95 elemType, err := typeOfField(f) 96 if err != nil { 97 return nil, err 98 } 99 elems[i] = elemType 100 rawNames[i] = toCamelCase(f.Name) 101 } 102 return &abi.Type{ 103 T: abi.TupleTy, 104 TupleElems: elems, 105 TupleRawName: typ.Name(), 106 TupleRawNames: rawNames, 107 TupleType: typ, 108 }, nil 109 } 110 return nil, fmt.Errorf("unknown type %q", typ) 111 } 112 113 if abiType == "" { 114 // if no abiType is specified, return the basic type directly. 115 return &abiT, nil 116 } 117 118 abiT, ok := types[abiType] 119 if !ok { 120 return nil, fmt.Errorf("unknown abi type %q", abiType) 121 } 122 if abiT.GetType() != typ && !(typ == reflect.TypeFor[*big.Int]() && 123 (abiT.GetType().Kind() == reflect.Int16 || 124 abiT.GetType().Kind() == reflect.Int32 || 125 abiT.GetType().Kind() == reflect.Int64 || 126 abiT.GetType().Kind() == reflect.Uint16 || 127 abiT.GetType().Kind() == reflect.Uint32 || 128 abiT.GetType().Kind() == reflect.Uint64)) { 129 return nil, fmt.Errorf("tagged type %q does not match type %v", abiType, typ) 130 } 131 return &abiT, nil 132 } 133 134 var basicTypes = map[reflect.Type]abi.Type{ 135 reflect.TypeFor[bool](): {T: abi.BoolTy}, 136 reflect.TypeFor[byte](): {T: abi.UintTy, Size: 8}, 137 reflect.TypeFor[uint8](): {T: abi.UintTy, Size: 8}, 138 reflect.TypeFor[uint16](): {T: abi.UintTy, Size: 16}, 139 reflect.TypeFor[uint32](): {T: abi.UintTy, Size: 32}, 140 reflect.TypeFor[uint64](): {T: abi.UintTy, Size: 64}, 141 reflect.TypeFor[int8](): {T: abi.IntTy, Size: 8}, 142 reflect.TypeFor[int16](): {T: abi.IntTy, Size: 16}, 143 reflect.TypeFor[int32](): {T: abi.IntTy, Size: 32}, 144 reflect.TypeFor[int64](): {T: abi.IntTy, Size: 64}, 145 reflect.TypeFor[[1]byte](): {T: abi.FixedBytesTy, Size: 1}, 146 reflect.TypeFor[[2]byte](): {T: abi.FixedBytesTy, Size: 2}, 147 reflect.TypeFor[[3]byte](): {T: abi.FixedBytesTy, Size: 3}, 148 reflect.TypeFor[[4]byte](): {T: abi.FixedBytesTy, Size: 4}, 149 reflect.TypeFor[[5]byte](): {T: abi.FixedBytesTy, Size: 5}, 150 reflect.TypeFor[[6]byte](): {T: abi.FixedBytesTy, Size: 6}, 151 reflect.TypeFor[[7]byte](): {T: abi.FixedBytesTy, Size: 7}, 152 reflect.TypeFor[[8]byte](): {T: abi.FixedBytesTy, Size: 8}, 153 reflect.TypeFor[[9]byte](): {T: abi.FixedBytesTy, Size: 9}, 154 reflect.TypeFor[[10]byte](): {T: abi.FixedBytesTy, Size: 10}, 155 reflect.TypeFor[[11]byte](): {T: abi.FixedBytesTy, Size: 11}, 156 reflect.TypeFor[[12]byte](): {T: abi.FixedBytesTy, Size: 12}, 157 reflect.TypeFor[[13]byte](): {T: abi.FixedBytesTy, Size: 13}, 158 reflect.TypeFor[[14]byte](): {T: abi.FixedBytesTy, Size: 14}, 159 reflect.TypeFor[[15]byte](): {T: abi.FixedBytesTy, Size: 15}, 160 reflect.TypeFor[[16]byte](): {T: abi.FixedBytesTy, Size: 16}, 161 reflect.TypeFor[[17]byte](): {T: abi.FixedBytesTy, Size: 17}, 162 reflect.TypeFor[[18]byte](): {T: abi.FixedBytesTy, Size: 18}, 163 reflect.TypeFor[[19]byte](): {T: abi.FixedBytesTy, Size: 19}, 164 reflect.TypeFor[[20]byte](): {T: abi.FixedBytesTy, Size: 20}, 165 reflect.TypeFor[[21]byte](): {T: abi.FixedBytesTy, Size: 21}, 166 reflect.TypeFor[[22]byte](): {T: abi.FixedBytesTy, Size: 22}, 167 reflect.TypeFor[[23]byte](): {T: abi.FixedBytesTy, Size: 23}, 168 reflect.TypeFor[[24]byte](): {T: abi.FixedBytesTy, Size: 24}, 169 reflect.TypeFor[[25]byte](): {T: abi.FixedBytesTy, Size: 25}, 170 reflect.TypeFor[[26]byte](): {T: abi.FixedBytesTy, Size: 26}, 171 reflect.TypeFor[[27]byte](): {T: abi.FixedBytesTy, Size: 27}, 172 reflect.TypeFor[[28]byte](): {T: abi.FixedBytesTy, Size: 28}, 173 reflect.TypeFor[[29]byte](): {T: abi.FixedBytesTy, Size: 29}, 174 reflect.TypeFor[[30]byte](): {T: abi.FixedBytesTy, Size: 30}, 175 reflect.TypeFor[[31]byte](): {T: abi.FixedBytesTy, Size: 31}, 176 reflect.TypeFor[[32]byte](): {T: abi.FixedBytesTy, Size: 32}, 177 reflect.TypeFor[common.Address](): {T: abi.AddressTy, Size: 20}, 178 reflect.TypeFor[common.Hash](): {T: abi.FixedBytesTy, Size: 32}, 179 reflect.TypeFor[string](): {T: abi.StringTy}, 180 reflect.TypeFor[[]byte](): {T: abi.BytesTy}, 181 reflect.TypeFor[*big.Int](): {T: abi.UintTy, Size: 256}, 182 } 183 184 func toCamelCase(s string) string { 185 if len(s) == 0 { 186 return s 187 } 188 189 r := []rune(s) 190 191 var prevUp bool 192 for i := range len(r) { 193 if i == 0 && unicode.IsUpper(r[i]) { 194 prevUp = true 195 r[i] = unicode.ToLower(r[i]) 196 } else if unicode.IsUpper(r[i]) { 197 if prevUp { 198 r[i] = unicode.ToLower(r[i]) 199 } 200 prevUp = true 201 } else { 202 prevUp = false 203 } 204 } 205 206 return string(r) 207 }