code.vegaprotocol.io/vega@v0.79.0/core/datasource/external/ethcall/json_args.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package ethcall 17 18 import ( 19 "bytes" 20 "encoding/json" 21 "fmt" 22 "reflect" 23 "unsafe" 24 25 "github.com/ethereum/go-ethereum/accounts/abi" 26 ) 27 28 // JsonArgsToAny takes a list of arguments marshalled as JSON strings. 29 // It then uses the ethereum ABI to convert each JSON argument into the go type 30 // which corresponds to the ethereum type defined in the ABI for that argument. 31 func JsonArgsToAny(methodName string, jsonArgs []string, abiJSON []byte) ([]any, error) { 32 abi, err := abi.JSON(bytes.NewReader(abiJSON)) 33 if err != nil { 34 return nil, fmt.Errorf("unable to parse abi json: %w", err) 35 } 36 37 methodAbi, ok := abi.Methods[methodName] 38 if !ok { 39 return nil, fmt.Errorf("method %s not found in abi", methodName) 40 } 41 42 inputsAbi := methodAbi.Inputs 43 if len(inputsAbi) != len(jsonArgs) { 44 return nil, fmt.Errorf("expected %v arguments for method %s, got %v", len(inputsAbi), methodName, len(jsonArgs)) 45 } 46 47 args := []any{} 48 for i, jsonArg := range jsonArgs { 49 argType := inputsAbi[i].Type.GetType() 50 argIsPointer := argType.Kind() == reflect.Pointer 51 52 if argIsPointer { 53 argType = argType.Elem() 54 } 55 56 newArgValue := reflect.New(argType) // A reflect.Value of kind 'Pointer' to new instance of argType 57 58 // here we handle specifically this type because the type returned by GetType() method 59 // is a [32]uint8, which is not assignable by the json marshaller 60 // we then instantiate specifically a []byte 61 // then set the reflect instatiated type with unsafe (...) by addressing to the first 62 // element of the byte slice 63 if argType.String() == "[32]uint8" { 64 b := []byte{} 65 err := json.Unmarshal([]byte(jsonArg), &b) 66 if err != nil { 67 return nil, fmt.Errorf("unable to unmarshal json argument %s: %w", jsonArg, err) 68 } 69 newArgValue = reflect.NewAt(argType, unsafe.Pointer(&b[0])) 70 } else { 71 err := json.Unmarshal([]byte(jsonArg), newArgValue.Interface()) 72 if err != nil { 73 return nil, fmt.Errorf("unable to unmarshal json argument %s: %w", jsonArg, err) 74 } 75 } 76 77 if argIsPointer { 78 args = append(args, newArgValue.Interface()) 79 } else { 80 args = append(args, newArgValue.Elem().Interface()) 81 } 82 } 83 return args, nil 84 } 85 86 // AnyArgsToJson does the inverse of the JsonArgsToAny; takes a list of arguments in go types 87 // and marshals them to a list of JSON strings. 88 func AnyArgsToJson(args []any) ([]string, error) { 89 result := make([]string, 0, len(args)) 90 for _, arg := range args { 91 argJSON, err := json.Marshal(arg) 92 if err != nil { 93 return []string{}, fmt.Errorf("failed to json marshall args to JSON: %w", err) 94 } 95 result = append(result, string(argJSON)) 96 } 97 98 return result, nil 99 } 100 101 func CanonicalizeJSON(in []byte) ([]byte, error) { 102 var data interface{} 103 if err := json.Unmarshal(in, &data); err != nil { 104 return nil, fmt.Errorf("failed to unmarshal json: %w", err) 105 } 106 107 out, err := json.Marshal(data) 108 if err != nil { 109 return nil, fmt.Errorf("failed to marshal json: %w", err) 110 } 111 return out, nil 112 }