github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/parser/contract_call_test.go (about) 1 package parser 2 3 import ( 4 "errors" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 11 "github.com/ethereum/go-ethereum/accounts/abi" 12 "github.com/ethereum/go-ethereum/common" 13 ) 14 15 func TestParse_Encoding(t *testing.T) { 16 // Short 17 if p, err := ParseCall(`0xcdba2fd40000000000000000000000000000000000000000000000000000000000007a69`); err != nil { 18 t.Fatal(err) 19 } else { 20 if s := p.Encoded; s != `0xcdba2fd40000000000000000000000000000000000000000000000000000000000007a69` { 21 t.Fatal("wrong encoded value", s) 22 } 23 } 24 25 // Long one 26 long := "0x7087e4bd000000000000000000000000f503017d7baf7fbc0fff7492b751025c6a78179b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000076d61696e6e657400000000000000000000000000000000000000000000000000" 27 if p, err := ParseCall(long); err != nil { 28 t.Fatal(err) 29 } else { 30 if s := p.Encoded; s != long { 31 t.Fatal("wrong encoded value", s) 32 } 33 } 34 } 35 36 func TestParse_Selector(t *testing.T) { 37 // Invalid selector 38 if _, err := ParseCall(`0xcdba()`); !strings.Contains(err.Error(), errInvalidSelector.Error()) { 39 t.Fatal("expected errInvalidSelector, got:", err) 40 } 41 42 // No arguments 43 if parsed, err := ParseCall(`0xcdba2fd4()`); err != nil { 44 t.Fatal(err) 45 } else { 46 if value := parsed.SelectorCall.Selector.Value; value != `0xcdba2fd4` { 47 t.Fatal("wrong selector", value) 48 } 49 if argsLen := len(parsed.SelectorCall.Arguments); argsLen != 0 { 50 t.Fatal("wrong number of arguments", argsLen) 51 } 52 } 53 54 if parsed, err := ParseCall(`0x7087e4bd(trueblocks.eth,"mainnet")`); err != nil { 55 t.Fatal(err) 56 } else { 57 if value := parsed.SelectorCall.Selector.Value; value != `0x7087e4bd` { 58 t.Fatal("wrong selector", value) 59 } 60 if argsLen := len(parsed.SelectorCall.Arguments); argsLen != 2 { 61 t.Fatal("wrong number of arguments", argsLen) 62 } 63 } 64 65 // Arguments 66 if parsed, err := ParseCall(`0xcdba2fd4(1, true, false, 0xbeef, "string")`); err != nil { 67 t.Fatal(err) 68 } else { 69 if value := parsed.SelectorCall.Selector.Value; value != `0xcdba2fd4` { 70 t.Fatal("wrong selector", value) 71 } 72 if argValue := *parsed.SelectorCall.Arguments[0].Number.Int; argValue != 1 { 73 t.Fatal("wrong #1 input value", argValue) 74 } 75 if argValue := *parsed.SelectorCall.Arguments[1].Boolean; argValue != true { 76 t.Fatal("wrong #2 input value", argValue) 77 } 78 if argValue := *parsed.SelectorCall.Arguments[2].Boolean; argValue != false { 79 t.Fatal("wrong #3 input value", argValue) 80 } 81 if argValue := *parsed.SelectorCall.Arguments[3].Hex.String; argValue != "0xbeef" { 82 t.Fatal("wrong #4 input value", argValue) 83 } 84 if argValue := *parsed.SelectorCall.Arguments[4].String; argValue != "string" { 85 t.Fatal("wrong #5 input value", argValue) 86 } 87 } 88 89 // Hex parsing 90 if parsed, err := ParseCall(`0xcdba2fd4(0xdeadbeef, 0x6982508145454ce325ddbe47a25d4ec3d23119a1)`); err != nil { 91 t.Fatal(err) 92 } else { 93 if argsLen := len(parsed.SelectorCall.Arguments); argsLen != 2 { 94 t.Fatal("wrong inputs length:", argsLen) 95 } 96 97 if *parsed.SelectorCall.Arguments[0].Hex.String != "0xdeadbeef" { 98 t.Fatal("should parse into Hex.String") 99 } 100 if parsed.SelectorCall.Arguments[1].Hex.Address.Hex() != "0x6982508145454ce325ddbe47a25d4ec3d23119a1" { 101 t.Fatal("should parse into Hex.Address") 102 } 103 } 104 } 105 106 func TestParse_Function(t *testing.T) { 107 // Invalid selector 108 if _, err := ParseCall(`111()`); err == nil { 109 t.Fatal("expected parsing error") 110 } 111 112 // No arguments 113 if parsed, err := ParseCall(`transfer()`); err != nil { 114 t.Fatal(err) 115 } else { 116 if value := parsed.FunctionNameCall.Name; value != `transfer` { 117 t.Fatal("wrong function name", value) 118 } 119 if argsLen := len(parsed.FunctionNameCall.Arguments); argsLen != 0 { 120 t.Fatal("wrong number of arguments", argsLen) 121 } 122 } 123 124 // Correct Solidity identifiers 125 if parsed, err := ParseCall(`$dollar$_underscoreCamelCase125__()`); err != nil { 126 t.Fatal(err) 127 } else { 128 if value := parsed.FunctionNameCall.Name; value != `$dollar$_underscoreCamelCase125__` { 129 t.Fatal("wrong function name", value) 130 } 131 } 132 133 // Arguments 134 if parsed, err := ParseCall(`something(1, true, false, 0xbeef, "string")`); err != nil { 135 t.Fatal(err) 136 } else { 137 if value := parsed.FunctionNameCall.Name; value != `something` { 138 t.Fatal("wrong selector", value) 139 } 140 if argValue := *parsed.FunctionNameCall.Arguments[0].Number.Int; argValue != 1 { 141 t.Fatal("wrong #1 input value", argValue) 142 } 143 if argValue := *parsed.FunctionNameCall.Arguments[1].Boolean; argValue != true { 144 t.Fatal("wrong #2 input value", argValue) 145 } 146 if argValue := *parsed.FunctionNameCall.Arguments[2].Boolean; argValue != false { 147 t.Fatal("wrong #3 input value", argValue) 148 } 149 if argValue := *parsed.FunctionNameCall.Arguments[3].Hex.String; argValue != "0xbeef" { 150 t.Fatal("wrong #4 input value", argValue) 151 } 152 if argValue := *parsed.FunctionNameCall.Arguments[4].String; argValue != "string" { 153 t.Fatal("wrong #5 input value", argValue) 154 } 155 } 156 157 // Hex parsing 158 if parsed, err := ParseCall(`somethingElse(0xdeadbeef, 0x6982508145454ce325ddbe47a25d4ec3d23119a1)`); err != nil { 159 t.Fatal(err) 160 } else { 161 if argsLen := len(parsed.FunctionNameCall.Arguments); argsLen != 2 { 162 t.Fatal("wrong inputs length:", argsLen) 163 } 164 165 if *parsed.FunctionNameCall.Arguments[0].Hex.String != "0xdeadbeef" { 166 t.Fatal("should parse into Hex.String") 167 } 168 if parsed.FunctionNameCall.Arguments[1].Hex.Address.Hex() != "0x6982508145454ce325ddbe47a25d4ec3d23119a1" { 169 t.Fatal("should parse into Hex.Address") 170 } 171 } 172 } 173 174 func TestParse_Numbers(t *testing.T) { 175 if parsed, err := ParseCall(`doSomething(1, -2, 115792089237316195423570985008687907853269984665640564039457584007913129639935)`); err != nil { 176 t.Fatal(err) 177 } else { 178 if argsLen := len(parsed.FunctionNameCall.Arguments); argsLen != 3 { 179 t.Fatal("wrong inputs length:", argsLen) 180 } 181 182 if value := *parsed.FunctionNameCall.Arguments[0].Number.Int; value != 1 { 183 t.Fatal("wrong uint value:", value) 184 } 185 if value := *parsed.FunctionNameCall.Arguments[1].Number.Int; value != -2 { 186 t.Fatal("wrong int value:", value) 187 } 188 if value := parsed.FunctionNameCall.Arguments[2].Number.Big.String(); value != "115792089237316195423570985008687907853269984665640564039457584007913129639935" { 189 t.Fatal("wrong big value:", value) 190 } 191 } 192 } 193 194 // This comes from go-ethereum's abi_test.go, we will use it to 195 // test type conversion (our types -> go-ethereum) 196 const packTestAbiSource = ` 197 [ 198 { "type" : "function", "name" : ""}, 199 { "type" : "function", "name" : "string", "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, 200 { "type" : "function", "name" : "bool", "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, 201 { "type" : "function", "name" : "address", "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, 202 { "type" : "function", "name" : "uint64", "inputs" : [ { "name" : "inputs", "type" : "uint64" } ] }, 203 { "type" : "function", "name" : "uint256", "inputs" : [ { "name" : "inputs", "type" : "uint256" } ] }, 204 { "type" : "function", "name" : "int8", "inputs" : [ { "name" : "inputs", "type" : "int8" } ] }, 205 { "type" : "function", "name" : "int64", "inputs" : [ { "name" : "inputs", "type" : "int64" } ] }, 206 { "type" : "function", "name" : "int256", "inputs" : [ { "name" : "inputs", "type" : "int256" } ] }, 207 { "type" : "function", "name" : "bytes4", "inputs" : [ { "name" : "inputs", "type" : "bytes4" } ] }, 208 { "type" : "function", "name" : "bytes32", "inputs" : [ { "name" : "inputs", "type" : "bytes32" } ] } 209 ]` 210 211 func TestArgument_AbiType(t *testing.T) { 212 testAbi, err := abi.JSON(strings.NewReader(packTestAbiSource)) 213 if err != nil { 214 panic(err) 215 } 216 int256 := base.NewWei(0) 217 _, ok := int256.SetString("-57896044618658097711785492504343953926634992332820282019728792003956564819968", 0) 218 if !ok { 219 t.Fatal("cannot set int256 value") 220 } 221 222 type fields struct { 223 String *ArgString 224 Number *ArgNumber 225 Boolean *ArgBool 226 Hex *ArgHex 227 } 228 type args struct { 229 abiType *abi.Type 230 } 231 tests := []struct { 232 name string 233 fields fields 234 args args 235 want any 236 wantErr bool 237 }{ 238 { 239 name: "bytes4 argument", 240 fields: fields{ 241 Hex: &ArgHex{ 242 String: utils.PointerOf("0x80ac58cd"), 243 }, 244 }, 245 args: args{ 246 abiType: &testAbi.Methods["bytes4"].Inputs[0].Type, 247 }, 248 want: [4]byte{128, 172, 88, 205}, 249 }, 250 { 251 name: "int8 argument", 252 fields: fields{ 253 Number: &ArgNumber{ 254 Int: utils.PointerOf(int64(-128)), 255 }, 256 }, 257 args: args{ 258 abiType: &testAbi.Methods["int8"].Inputs[0].Type, 259 }, 260 want: int8(-128), 261 }, 262 { 263 name: "int64 argument", 264 fields: fields{ 265 Number: &ArgNumber{ 266 Int: utils.PointerOf(int64(-9223372036854775808)), 267 }, 268 }, 269 args: args{ 270 abiType: &testAbi.Methods["int64"].Inputs[0].Type, 271 }, 272 want: int64(-9223372036854775808), 273 }, 274 { 275 name: "int256 argument", 276 fields: fields{ 277 Number: &ArgNumber{ 278 Big: int256, 279 }, 280 }, 281 args: args{ 282 abiType: &testAbi.Methods["int256"].Inputs[0].Type, 283 }, 284 want: int256, 285 }, 286 { 287 name: "address argument", 288 fields: fields{ 289 Hex: &ArgHex{ 290 Address: utils.PointerOf(base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b")), 291 }, 292 }, 293 args: args{ 294 abiType: &testAbi.Methods["address"].Inputs[0].Type, 295 }, 296 want: common.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b"), 297 }, 298 } 299 for _, tt := range tests { 300 t.Run(tt.name, func(t *testing.T) { 301 a := &ContractArgument{ 302 String: tt.fields.String, 303 Number: tt.fields.Number, 304 Boolean: tt.fields.Boolean, 305 Hex: tt.fields.Hex, 306 } 307 got, err := a.AbiType(tt.args.abiType) 308 if (err != nil) != tt.wantErr { 309 t.Errorf("Argument.ToAbiType() error = %v, wantErr %v", err, tt.wantErr) 310 return 311 } 312 if !reflect.DeepEqual(got, tt.want) { 313 t.Errorf("Argument.ToAbiType() = %v, want %v", got, tt.want) 314 } 315 }) 316 } 317 } 318 319 func TestArgument_AbiType_Errors(t *testing.T) { 320 testAbi, err := abi.JSON(strings.NewReader(packTestAbiSource)) 321 if err != nil { 322 panic(err) 323 } 324 325 // the second argument is string instead of address 326 parsed, err := ParseCall(`someFunc(0x6982508145454ce325ddbe47a25d4ec3d23119a1, "0x6982508145454ce325ddbe47a25d4ec3d23119a1")`) 327 if err != nil { 328 t.Fatal(err) 329 } 330 if _, err := parsed.FunctionNameCall.Arguments[0].AbiType(&testAbi.Methods["address"].Inputs[0].Type); err != nil { 331 t.Fatal(err) 332 } 333 _, err = parsed.FunctionNameCall.Arguments[1].AbiType(&testAbi.Methods["address"].Inputs[0].Type) 334 expected := errors.New(`expected address, but got string "0x6982508145454ce325ddbe47a25d4ec3d23119a1"`) 335 if err.Error() != expected.Error() { 336 t.Fatal("got wrong error:", err, "expected:", expected) 337 } 338 339 parsed, err = ParseCall(`someBool(111)`) 340 if err != nil { 341 t.Fatal(err) 342 } 343 _, err = parsed.FunctionNameCall.Arguments[0].AbiType(&testAbi.Methods["bool"].Inputs[0].Type) 344 expected = errors.New(`expected bool, but got integer "111"`) 345 if err.Error() != expected.Error() { 346 t.Fatal("got wrong error:", err, "expected:", expected) 347 } 348 349 parsed, err = ParseCall(`someBytes32("hello")`) 350 if err != nil { 351 t.Fatal(err) 352 } 353 _, err = parsed.FunctionNameCall.Arguments[0].AbiType(&testAbi.Methods["bytes32"].Inputs[0].Type) 354 expected = errors.New(`expected hash, but got string "hello"`) 355 if err.Error() != expected.Error() { 356 t.Fatal("got wrong error:", err, "expected:", expected) 357 } 358 }