github.com/lmittmann/w3@v0.20.0/func_test.go (about) 1 package w3_test 2 3 import ( 4 "bytes" 5 "errors" 6 "math/big" 7 "strconv" 8 "testing" 9 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/google/go-cmp/cmp" 12 "github.com/google/go-cmp/cmp/cmpopts" 13 "github.com/lmittmann/w3" 14 "github.com/lmittmann/w3/internal" 15 "github.com/lmittmann/w3/w3types" 16 ) 17 18 func TestNewFunc(t *testing.T) { 19 tests := []struct { 20 Signature string 21 Returns string 22 Tuples []any 23 WantFunc *w3.Func 24 }{ 25 { 26 Signature: "transfer(address,uint256)", 27 Returns: "bool", 28 WantFunc: &w3.Func{ 29 Signature: "transfer(address,uint256)", 30 Selector: [4]byte{0xa9, 0x05, 0x9c, 0xbb}, 31 }, 32 }, 33 { 34 Signature: "transfer(address recipient, uint256 amount)", 35 Returns: "bool success", 36 WantFunc: &w3.Func{ 37 Signature: "transfer(address,uint256)", 38 Selector: [4]byte{0xa9, 0x05, 0x9c, 0xbb}, 39 }, 40 }, 41 { 42 Signature: "testTuple(tuple)", 43 Returns: "bool", 44 Tuples: []any{tuple{}}, 45 WantFunc: &w3.Func{ 46 Signature: "testTuple((address,uint256))", 47 Selector: [4]byte{0xa0, 0x54, 0xdf, 0xd5}, 48 }, 49 }, 50 { 51 Signature: "testTuple(tupleWithTag)", 52 Returns: "bool", 53 Tuples: []any{tupleWithTag{}}, 54 WantFunc: &w3.Func{ 55 Signature: "testTuple((address,uint128))", 56 Selector: [4]byte{0xa8, 0x97, 0xff, 0xb3}, 57 }, 58 }, 59 { 60 Signature: "testTuple(tupleWithNesting)", 61 Returns: "bool", 62 Tuples: []any{tupleWithNesting{}}, 63 WantFunc: &w3.Func{ 64 Signature: "testTuple((address,(address,uint256)))", 65 Selector: [4]byte{0xff, 0x4c, 0x07, 0xd1}, 66 }, 67 }, 68 } 69 70 for i, test := range tests { 71 t.Run(strconv.Itoa(i), func(t *testing.T) { 72 gotFunc, err := w3.NewFunc(test.Signature, test.Returns, test.Tuples...) 73 if err != nil { 74 t.Fatalf("Failed to create new FUnc: %v", err) 75 } 76 77 if diff := cmp.Diff(test.WantFunc, gotFunc, 78 cmpopts.IgnoreFields(w3.Func{}, "Args", "Returns", "name"), 79 ); diff != "" { 80 t.Fatalf("(-want, +got)\n%s", diff) 81 } 82 }) 83 } 84 } 85 86 func TestFuncEncodeArgs(t *testing.T) { 87 tests := []struct { 88 Func w3types.Func 89 Args []any 90 Want []byte 91 }{ 92 { 93 Func: w3.MustNewFunc("balanceOf(address who)", "uint256 balance"), 94 Args: []any{w3.A("0x000000000000000000000000000000000000dEaD")}, 95 Want: w3.B("0x70a08231000000000000000000000000000000000000000000000000000000000000dEaD"), 96 }, 97 { 98 Func: w3.MustNewFunc("transfer(address recipient, uint256 amount)", "bool success"), 99 Args: []any{w3.A("0x000000000000000000000000000000000000dEaD"), big.NewInt(1)}, 100 Want: w3.B("0xa9059cbb000000000000000000000000000000000000000000000000000000000000dEaD0000000000000000000000000000000000000000000000000000000000000001"), 101 }, 102 { 103 Func: w3.MustNewFunc("name()", "string"), 104 Args: []any{}, 105 Want: w3.B("0x06fdde03"), 106 }, 107 { 108 Func: w3.MustNewFunc("withdraw(uint256)", ""), 109 Args: []any{big.NewInt(1)}, 110 Want: w3.B("0x2e1a7d4d0000000000000000000000000000000000000000000000000000000000000001"), 111 }, 112 { 113 Func: w3.MustNewFunc("getAmountsOut(uint256,address[])", "uint256[]"), 114 Args: []any{big.NewInt(1), []common.Address{w3.A("0x1111111111111111111111111111111111111111"), w3.A("0x2222222222222222222222222222222222222222")}}, 115 Want: w3.B("0xd06ca61f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222"), 116 }, 117 { 118 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 119 Args: []any{&tuple{ 120 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 121 Arg1: big.NewInt(42), 122 }}, 123 Want: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 124 }, 125 { 126 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 127 Args: []any{&tupleWithWrongOrder{ 128 Arg1: big.NewInt(42), 129 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 130 }}, 131 Want: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 132 }, 133 { 134 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 135 Args: []any{&tupleWithMoreArgs{ 136 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 137 Arg1: big.NewInt(42), 138 Arg2: big.NewInt(7), 139 }}, 140 Want: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 141 }, 142 { 143 Func: w3.MustNewFunc("test((address arg0, uint256 arg1)[] args)", ""), 144 Args: []any{ 145 []tuple{ 146 {Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: big.NewInt(7)}, 147 {Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: big.NewInt(42)}, 148 }, 149 }, 150 Want: w3.B("0xae4f5efa00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000070000000000000000000000002222222222222222222222222222222222222222000000000000000000000000000000000000000000000000000000000000002a"), 151 }, 152 { 153 Func: w3.MustNewFunc("test((address arg0, bytes arg1)[] calls)", ""), 154 Args: []any{ 155 []tupleWithBytes{ 156 {Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: w3.B("0xc0fe")}, 157 {Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: w3.B("0xdeadbeef")}, 158 }, 159 }, 160 Want: w3.B("0x3a91207700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002c0fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000222222222222222222222222222222222222222200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"), 161 }, 162 { 163 Func: w3.MustNewFunc("test(tupleWithBytes[] calls)", "", tupleWithBytes{}), 164 Args: []any{ 165 []tupleWithBytes{ 166 {Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: w3.B("0xc0fe")}, 167 {Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: w3.B("0xdeadbeef")}, 168 }, 169 }, 170 Want: w3.B("0x3a91207700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002c0fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000222222222222222222222222222222222222222200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"), 171 }, 172 { 173 Func: w3.MustNewFunc("test(uint[])", ""), 174 Args: []any{ 175 []*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)}, 176 }, 177 Want: w3.B("0xca16068400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 178 }, 179 { 180 Func: w3.MustNewFunc("test(uint[2])", ""), 181 Args: []any{ 182 [2]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)}, 183 }, 184 Want: w3.B("0xf1635056000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 185 }, 186 { 187 Func: w3.MustNewFunc("test(uint64[])", ""), 188 Args: []any{ 189 []uint64{0xdead, 0xbeef}, 190 }, 191 Want: w3.B("0xd3469fbd00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 192 }, 193 { 194 Func: w3.MustNewFunc("test(uint64[2])", ""), 195 Args: []any{ 196 [2]uint64{0xdead, 0xbeef}, 197 }, 198 Want: w3.B("0x533d6285000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 199 }, 200 { 201 Func: w3.MustNewFunc("testTuple(tuple)", "bool", tuple{}), 202 Args: []any{&tuple{ 203 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 204 Arg1: big.NewInt(42), 205 }}, 206 Want: w3.B("0xa054dfd5000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 207 }, 208 { // https://github.com/lmittmann/w3/issues/35 209 Func: w3.MustNewFunc("test(((address to)[] recipients) param)", ""), 210 Args: []any{ 211 &tupleIssue35{Recipients: []struct { 212 To common.Address 213 }{ 214 {To: w3.A("0x1111111111111111111111111111111111111111")}, 215 {To: w3.A("0x2222222222222222222222222222222222222222")}, 216 }}, 217 }, 218 Want: w3.B("0xf61d1a2a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222"), 219 }, 220 } 221 222 for i, test := range tests { 223 t.Run(strconv.Itoa(i), func(t *testing.T) { 224 encodedInput, err := test.Func.EncodeArgs(test.Args...) 225 if err != nil { 226 t.Fatalf("Failed to encode args: %v", err) 227 } 228 229 if !bytes.Equal(test.Want, encodedInput) { 230 t.Fatalf("(-want, +got)\n- 0x%x\n+ 0x%x", test.Want, encodedInput) 231 } 232 }) 233 } 234 } 235 236 func TestFuncDecodeArgs(t *testing.T) { 237 tests := []struct { 238 Func w3types.Func 239 Input []byte 240 Args []any 241 WantArgs []any 242 WantErr error 243 }{ 244 { 245 Func: w3.MustNewFunc("test(address)", ""), 246 Input: w3.B("0xbb29998e000000000000000000000000000000000000000000000000000000000000c0fe"), 247 Args: []any{new(common.Address)}, 248 WantArgs: []any{w3.APtr("0x000000000000000000000000000000000000c0Fe")}, 249 }, 250 { 251 Func: w3.MustNewFunc("test(uint256)", ""), 252 Input: w3.B("0x29e99f07000000000000000000000000000000000000000000000000000000000000002a"), 253 Args: []any{new(big.Int)}, 254 WantArgs: []any{big.NewInt(42)}, 255 }, 256 { 257 Func: w3.MustNewFunc("test(bool)", ""), 258 Input: w3.B("0x36091dff0000000000000000000000000000000000000000000000000000000000000001"), 259 Args: []any{ptr(false)}, 260 WantArgs: []any{ptr(true)}, 261 }, 262 { 263 Func: w3.MustNewFunc("test(bytes32)", ""), 264 Input: w3.B("0x993723210102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), 265 Args: []any{&[32]byte{}}, 266 WantArgs: []any{&[32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}}, 267 }, 268 { 269 Func: w3.MustNewFunc("test(bytes32)", ""), 270 Input: w3.B("0x993723210102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), 271 Args: []any{new(common.Hash)}, 272 WantArgs: []any{ptr(w3.H("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"))}, 273 }, 274 { 275 Func: w3.MustNewFunc("test(bytes)", ""), 276 Input: w3.B("0x2f570a23000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"), 277 Args: []any{&[]byte{}}, 278 WantArgs: []any{&[]byte{1, 2, 3}}, 279 }, 280 { 281 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 282 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 283 Args: []any{new(tuple)}, 284 WantArgs: []any{&tuple{ 285 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 286 Arg1: big.NewInt(42), 287 }}, 288 }, 289 { 290 Func: w3.MustNewFunc("test(tuple)", "", tuple{}), 291 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 292 Args: []any{new(tuple)}, 293 WantArgs: []any{&tuple{ 294 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 295 Arg1: big.NewInt(42), 296 }}, 297 }, 298 { 299 // https://github.com/lmittmann/w3/issues/67 300 Func: w3.MustNewFunc("test((address, uint256))", ""), 301 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 302 Args: []any{nil}, 303 WantArgs: []any{nil}, 304 }, 305 { 306 // https://github.com/lmittmann/w3/issues/67 307 Func: w3.MustNewFunc("test((address, uint256))", ""), 308 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 309 Args: []any{new(tuple)}, 310 WantArgs: []any{&tuple{ 311 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 312 Arg1: big.NewInt(42), 313 }}, 314 }, 315 { 316 // https://github.com/lmittmann/w3/issues/67 317 Func: w3.MustNewFunc("test((address, (address, uint256)))", ""), 318 Input: w3.B("0x1a68b84c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000002a"), 319 Args: []any{new(tupleNested)}, 320 WantArgs: []any{&tupleNested{ 321 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 322 Arg1: tuple{ 323 Arg0: w3.A("0x000000000000000000000000000000000000dEaD"), 324 Arg1: big.NewInt(42), 325 }, 326 }}, 327 }, 328 { 329 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 330 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 331 Args: []any{new(tupleWithWrongOrder)}, 332 WantArgs: []any{&tupleWithWrongOrder{ 333 Arg1: big.NewInt(42), 334 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 335 }}, 336 }, 337 { 338 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 339 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 340 Args: []any{new(tupleWithMoreArgs)}, 341 WantArgs: []any{&tupleWithMoreArgs{ 342 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 343 Arg1: big.NewInt(42), 344 }}, 345 }, 346 { // https://github.com/lmittmann/w3/issues/22 347 Func: w3.MustNewFunc("transfer(address recipient, uint256 amount)", "bool success"), 348 Input: w3.B("0x"), 349 Args: []any{new(common.Address), new(big.Int)}, 350 WantErr: errors.New("w3: insufficient input length"), 351 }, 352 { 353 Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""), 354 Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 355 Args: []any{new(tupleWithUnexportedProperty)}, 356 WantArgs: []any{&tupleWithUnexportedProperty{ 357 Arg1: big.NewInt(42), 358 }}, 359 }, 360 { 361 Func: w3.MustNewFunc("test((address arg0, bytes arg1)[] calls)", ""), 362 Input: w3.B("0x3a91207700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002c0fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000222222222222222222222222222222222222222200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"), 363 Args: []any{&[]*tupleWithBytes{}}, 364 WantArgs: []any{ 365 &[]*tupleWithBytes{ 366 {Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: w3.B("0xc0fe")}, 367 {Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: w3.B("0xdeadbeef")}, 368 }, 369 }, 370 }, 371 { 372 Func: w3.MustNewFunc("test(uint[])", ""), 373 Input: w3.B("0xca16068400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 374 Args: []any{new([]*big.Int)}, 375 WantArgs: []any{ 376 &[]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)}, 377 }, 378 }, 379 { 380 Func: w3.MustNewFunc("test(uint[2])", ""), 381 Input: w3.B("0xf1635056000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 382 Args: []any{new([2]*big.Int)}, 383 WantArgs: []any{ 384 &[2]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)}, 385 }, 386 }, 387 { 388 Func: w3.MustNewFunc("test(uint64[])", ""), 389 Input: w3.B("0xd3469fbd00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 390 Args: []any{new([]uint64)}, 391 WantArgs: []any{ 392 &[]uint64{0xdead, 0xbeef}, 393 }, 394 }, 395 { 396 Func: w3.MustNewFunc("test(uint64[2])", ""), 397 Input: w3.B("0x533d6285000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"), 398 Args: []any{new([2]uint64)}, 399 WantArgs: []any{ 400 &[2]uint64{0xdead, 0xbeef}, 401 }, 402 }, 403 { 404 Func: w3.MustNewFunc("testTuple(tuple)", "bool", tuple{}), 405 Input: w3.B("0xa054dfd5000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 406 Args: []any{new(tuple)}, 407 WantArgs: []any{&tuple{ 408 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 409 Arg1: big.NewInt(42), 410 }}, 411 }, 412 { // https://github.com/lmittmann/w3/issues/35 413 Func: w3.MustNewFunc("test(((address to)[] recipients) param)", ""), 414 Input: w3.B("0xf61d1a2a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222"), 415 Args: []any{new(tupleIssue35)}, 416 WantArgs: []any{ 417 &tupleIssue35{Recipients: []struct { 418 To common.Address 419 }{ 420 {To: w3.A("0x1111111111111111111111111111111111111111")}, 421 {To: w3.A("0x2222222222222222222222222222222222222222")}, 422 }}, 423 }, 424 }, 425 { 426 Func: w3.MustNewFunc("test(address)", ""), 427 Input: w3.B("0xffffffff000000000000000000000000000000000000000000000000000000000000c0fe"), 428 Args: []any{new(common.Address)}, 429 WantErr: errors.New("w3: input does not match selector"), 430 }, 431 } 432 433 for i, test := range tests { 434 t.Run(strconv.Itoa(i), func(t *testing.T) { 435 err := test.Func.DecodeArgs(test.Input, test.Args...) 436 if diff := cmp.Diff(test.WantErr, err, internal.EquateErrors()); diff != "" { 437 t.Fatalf("Err: (-want, +got)\n%s", diff) 438 } 439 if err != nil { 440 return 441 } 442 443 if diff := cmp.Diff(test.WantArgs, test.Args, 444 cmp.AllowUnexported(big.Int{}, tupleWithUnexportedProperty{}), 445 ); diff != "" { 446 t.Fatalf("Args: (-want, +got)\n%s", diff) 447 } 448 }) 449 } 450 } 451 452 func TestFuncDecodeReturns(t *testing.T) { 453 tests := []struct { 454 Func w3types.Func 455 Output []byte 456 Returns []any 457 WantReturns []any 458 }{ 459 { 460 Func: w3.MustNewFunc("test()", "address"), 461 Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe"), 462 Returns: []any{new(common.Address)}, 463 WantReturns: []any{w3.APtr("0x000000000000000000000000000000000000c0Fe")}, 464 }, 465 { 466 Func: w3.MustNewFunc("test()", "uint256"), 467 Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000002a"), 468 Returns: []any{new(big.Int)}, 469 WantReturns: []any{big.NewInt(42)}, 470 }, 471 { 472 Func: w3.MustNewFunc("test()", "bool"), 473 Output: w3.B("0x0000000000000000000000000000000000000000000000000000000000000001"), 474 Returns: []any{ptr(false)}, 475 WantReturns: []any{ptr(true)}, 476 }, 477 { 478 Func: w3.MustNewFunc("test()", "bytes32"), 479 Output: w3.B("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), 480 Returns: []any{&[32]byte{}}, 481 WantReturns: []any{&[32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}}, 482 }, 483 { 484 Func: w3.MustNewFunc("test()", "bytes32"), 485 Output: w3.B("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), 486 Returns: []any{new(common.Hash)}, 487 WantReturns: []any{ptr(w3.H("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"))}, 488 }, 489 { 490 Func: w3.MustNewFunc("test()", "bytes"), 491 Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"), 492 Returns: []any{&[]byte{}}, 493 WantReturns: []any{&[]byte{1, 2, 3}}, 494 }, 495 { // https://github.com/lmittmann/w3/issues/25 496 Func: w3.MustNewFunc("test()", "(address arg0, uint256 arg1)"), 497 Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 498 Returns: []any{new(tuple)}, 499 WantReturns: []any{&tuple{ 500 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 501 Arg1: big.NewInt(42), 502 }}, 503 }, 504 { 505 Func: w3.MustNewFunc("test()", "tuple", tuple{}), 506 Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"), 507 Returns: []any{new(tuple)}, 508 WantReturns: []any{&tuple{ 509 Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"), 510 Arg1: big.NewInt(42), 511 }}, 512 }, 513 } 514 515 for i, test := range tests { 516 t.Run(strconv.Itoa(i), func(t *testing.T) { 517 if err := test.Func.DecodeReturns(test.Output, test.Returns...); err != nil { 518 t.Fatalf("Failed to decode returns: %v", err) 519 } 520 if diff := cmp.Diff(test.WantReturns, test.Returns, cmp.AllowUnexported(big.Int{})); diff != "" { 521 t.Fatalf("(-want, +got)\n%s", diff) 522 } 523 }) 524 } 525 } 526 527 func ptr[T any](v T) *T { return &v } 528 529 type tuple struct { 530 Arg0 common.Address 531 Arg1 *big.Int 532 } 533 534 type tupleWithTag struct { 535 Arg0 common.Address `abitype:"address"` 536 Arg1 *big.Int `abitype:"uint128"` 537 } 538 539 type tupleWithNesting struct { 540 Arg0 common.Address 541 Arg1 tuple 542 } 543 544 type tupleWithBytes struct { 545 Arg0 common.Address 546 Arg1 []byte 547 } 548 549 type tupleWithUnexportedProperty struct { 550 //lint:ignore U1000 ignore unused field 551 arg0 common.Address 552 Arg1 *big.Int 553 } 554 555 type tupleWithWrongOrder struct { 556 Arg1 *big.Int 557 Arg0 common.Address 558 } 559 560 type tupleWithMoreArgs struct { 561 Arg0 common.Address 562 Arg1 *big.Int 563 Arg2 *big.Int // Arg that is missing in func signature 564 } 565 566 type tupleIssue35 struct { 567 Recipients []struct { 568 To common.Address 569 } 570 } 571 572 type tupleNested struct { 573 Arg0 common.Address 574 Arg1 tuple 575 } 576 577 func BenchmarkFuncEncode(b *testing.B) { 578 var ( 579 funcSwap = w3.MustNewFunc("swap(uint amount0Out, uint amount1Out, address to, bytes data)", "") 580 amount0Out = big.NewInt(1000000000000000000) // 1 ETH 581 amount1Out = big.NewInt(0) // 0 token 582 to = w3.A("0x000000000000000000000000000000000000c0Fe") 583 data = []byte{} 584 ) 585 586 b.ReportAllocs() 587 b.ResetTimer() 588 for range b.N { 589 funcSwap.EncodeArgs(amount0Out, amount1Out, to, data) 590 } 591 }