github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/newcmd/contract/parse.go (about) 1 // Copyright (c) 2022 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package contract 7 8 import ( 9 "encoding/hex" 10 "encoding/json" 11 "fmt" 12 "math/big" 13 "reflect" 14 "strconv" 15 "strings" 16 17 "github.com/ethereum/go-ethereum/accounts/abi" 18 "github.com/ethereum/go-ethereum/common" 19 "github.com/iotexproject/iotex-address/address" 20 "github.com/pkg/errors" 21 22 "github.com/iotexproject/iotex-core/pkg/util/addrutil" 23 ) 24 25 // ErrInvalidArg indicates argument is invalid 26 var ( 27 ErrInvalidArg = fmt.Errorf("invalid argument") 28 ) 29 30 func parseAbi(abiBytes []byte) (*abi.ABI, error) { 31 parsedAbi, err := abi.JSON(strings.NewReader(string(abiBytes))) 32 if err != nil { 33 return nil, errors.Wrap(err, "failed to unmarshal abi") 34 } 35 return &parsedAbi, nil 36 } 37 38 func parseInput(rowInput string) (map[string]interface{}, error) { 39 var input map[string]interface{} 40 if err := json.Unmarshal([]byte(rowInput), &input); err != nil { 41 return nil, errors.Wrap(err, "failed to unmarshal arguments") 42 } 43 return input, nil 44 } 45 46 func parseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) { 47 resultBytes, err := hex.DecodeString(result) 48 if err != nil { 49 return "", errors.Wrap(err, "failed to decode result") 50 } 51 52 var ( 53 outputArgs = targetAbi.Methods[targetMethod].Outputs 54 tupleStr = make([]string, 0, len(outputArgs)) 55 ) 56 57 v, err := targetAbi.Unpack(targetMethod, resultBytes) 58 if err != nil { 59 return "", errors.Wrap(err, "failed to parse output") 60 } 61 62 if len(outputArgs) == 1 { 63 elemStr, _ := parseOutputArgument(v[0], &outputArgs[0].Type) 64 return elemStr, nil 65 } 66 67 for i, field := range v { 68 elemStr, _ := parseOutputArgument(field, &outputArgs[i].Type) 69 tupleStr = append(tupleStr, outputArgs[i].Name+":"+elemStr) 70 } 71 return "{" + strings.Join(tupleStr, " ") + "}", nil 72 } 73 74 // parseInputArgument parses input's argument as golang variable 75 func parseInputArgument(t *abi.Type, arg interface{}) (interface{}, error) { 76 switch t.T { 77 case abi.BoolTy: 78 if reflect.TypeOf(arg).Kind() != reflect.Bool { 79 return nil, ErrInvalidArg 80 } 81 82 case abi.StringTy: 83 if reflect.TypeOf(arg).Kind() != reflect.String { 84 return nil, ErrInvalidArg 85 } 86 87 case abi.SliceTy: 88 if reflect.TypeOf(arg).Kind() != reflect.Slice { 89 return nil, ErrInvalidArg 90 } 91 92 slice := reflect.MakeSlice(t.GetType(), 0, t.Size) 93 94 s := reflect.ValueOf(arg) 95 for i := 0; i < s.Len(); i++ { 96 ele, err := parseInputArgument(t.Elem, s.Index(i).Interface()) 97 if err != nil { 98 return nil, err 99 } 100 slice = reflect.Append(slice, reflect.ValueOf(ele)) 101 } 102 103 arg = slice.Interface() 104 105 case abi.ArrayTy: 106 if reflect.TypeOf(arg).Kind() != reflect.Slice { 107 return nil, ErrInvalidArg 108 } 109 110 arrayType := reflect.ArrayOf(t.Size, t.Elem.GetType()) 111 array := reflect.New(arrayType).Elem() 112 113 s := reflect.ValueOf(arg) 114 for i := 0; i < s.Len(); i++ { 115 ele, err := parseInputArgument(t.Elem, s.Index(i).Interface()) 116 if err != nil { 117 return nil, err 118 } 119 array.Index(i).Set(reflect.ValueOf(ele)) 120 } 121 122 arg = array.Interface() 123 124 // support both of Ether address & IoTeX address input 125 case abi.AddressTy: 126 var err error 127 addrString, ok := arg.(string) 128 if !ok { 129 return nil, ErrInvalidArg 130 } 131 132 if common.IsHexAddress(addrString) { 133 arg = common.HexToAddress(addrString) 134 } else { 135 arg, err = addrutil.IoAddrToEvmAddr(addrString) 136 if err != nil { 137 return nil, err 138 } 139 } 140 141 // support both number & string input 142 case abi.IntTy: 143 var ok bool 144 var err error 145 146 k := reflect.TypeOf(arg).Kind() 147 if k != reflect.String && k != reflect.Float64 { 148 return nil, ErrInvalidArg 149 } 150 151 var value int64 152 switch t.Size { 153 case 8: 154 if k == reflect.String { 155 value, err = strconv.ParseInt(arg.(string), 10, 8) 156 arg = int8(value) 157 } else { 158 arg = int8(arg.(float64)) 159 } 160 case 16: 161 if k == reflect.String { 162 value, err = strconv.ParseInt(arg.(string), 10, 16) 163 arg = int16(value) 164 } else { 165 arg = int16(arg.(float64)) 166 } 167 case 32: 168 if k == reflect.String { 169 value, err = strconv.ParseInt(arg.(string), 10, 32) 170 arg = int32(value) 171 } else { 172 arg = int32(arg.(float64)) 173 } 174 case 64: 175 if k == reflect.String { 176 arg, err = strconv.ParseInt(arg.(string), 10, 64) 177 } else { 178 arg = int64(arg.(float64)) 179 } 180 default: 181 if k == reflect.String { 182 arg, ok = new(big.Int).SetString(arg.(string), 10) 183 if !ok { 184 return nil, ErrInvalidArg 185 } 186 } else { 187 arg = big.NewInt(int64(arg.(float64))) 188 } 189 } 190 191 if err != nil { 192 return nil, err 193 } 194 195 // support both number & string input 196 case abi.UintTy: 197 var ok bool 198 var err error 199 200 k := reflect.TypeOf(arg).Kind() 201 if k != reflect.String && k != reflect.Float64 { 202 return nil, ErrInvalidArg 203 } 204 205 var value uint64 206 switch t.Size { 207 case 8: 208 if k == reflect.String { 209 value, err = strconv.ParseUint(arg.(string), 10, 8) 210 arg = uint8(value) 211 } else { 212 arg = uint8(arg.(float64)) 213 } 214 case 16: 215 if k == reflect.String { 216 value, err = strconv.ParseUint(arg.(string), 10, 16) 217 arg = uint16(value) 218 } else { 219 arg = uint16(arg.(float64)) 220 } 221 case 32: 222 if k == reflect.String { 223 value, err = strconv.ParseUint(arg.(string), 10, 32) 224 arg = uint32(value) 225 } else { 226 arg = uint32(arg.(float64)) 227 } 228 case 64: 229 if k == reflect.String { 230 arg, err = strconv.ParseUint(arg.(string), 10, 64) 231 } else { 232 arg = uint64(arg.(float64)) 233 } 234 default: 235 if k == reflect.String { 236 arg, ok = new(big.Int).SetString(arg.(string), 10) 237 if !ok { 238 return nil, ErrInvalidArg 239 } 240 } else { 241 arg = big.NewInt(int64(arg.(float64))) 242 } 243 244 if arg.(*big.Int).Cmp(big.NewInt(0)) < 0 { 245 return nil, ErrInvalidArg 246 } 247 } 248 249 if err != nil { 250 return nil, err 251 } 252 253 case abi.BytesTy: 254 if reflect.TypeOf(arg).Kind() != reflect.String { 255 return nil, ErrInvalidArg 256 } 257 258 bytecode, err := decodeBytecode(arg.(string)) 259 if err != nil { 260 return nil, err 261 } 262 263 bytes := reflect.MakeSlice(t.GetType(), 0, len(bytecode)) 264 265 for _, oneByte := range bytecode { 266 bytes = reflect.Append(bytes, reflect.ValueOf(oneByte)) 267 } 268 269 arg = bytes.Interface() 270 271 case abi.FixedBytesTy, abi.FunctionTy: 272 if reflect.TypeOf(arg).Kind() != reflect.String { 273 return nil, ErrInvalidArg 274 } 275 276 bytecode, err := decodeBytecode(arg.(string)) 277 if err != nil { 278 return nil, err 279 } 280 281 if t.Size != len(bytecode) { 282 return nil, ErrInvalidArg 283 } 284 285 bytesType := reflect.ArrayOf(t.Size, reflect.TypeOf(uint8(0))) 286 bytes := reflect.New(bytesType).Elem() 287 288 for i, oneByte := range bytecode { 289 bytes.Index(i).Set(reflect.ValueOf(oneByte)) 290 } 291 292 arg = bytes.Interface() 293 294 default: 295 return nil, ErrInvalidArg 296 } 297 return arg, nil 298 } 299 300 // parseOutputArgument parses output's argument as human-readable string 301 func parseOutputArgument(v interface{}, t *abi.Type) (string, bool) { 302 str := fmt.Sprint(v) 303 ok := false 304 305 switch t.T { 306 case abi.StringTy, abi.BoolTy: 307 // case abi.StringTy & abi.BoolTy can be handled by fmt.Sprint() 308 ok = true 309 310 case abi.TupleTy: 311 if reflect.TypeOf(v).Kind() == reflect.Struct { 312 ok = true 313 314 tupleStr := make([]string, 0, len(t.TupleElems)) 315 for i, elem := range t.TupleElems { 316 elemStr, elemOk := parseOutputArgument(reflect.ValueOf(v).Field(i).Interface(), elem) 317 tupleStr = append(tupleStr, t.TupleRawNames[i]+":"+elemStr) 318 ok = ok && elemOk 319 } 320 321 str = "{" + strings.Join(tupleStr, " ") + "}" 322 } 323 324 case abi.SliceTy, abi.ArrayTy: 325 if reflect.TypeOf(v).Kind() == reflect.Slice || reflect.TypeOf(v).Kind() == reflect.Array { 326 ok = true 327 328 value := reflect.ValueOf(v) 329 sliceStr := make([]string, 0, value.Len()) 330 for i := 0; i < value.Len(); i++ { 331 elemStr, elemOk := parseOutputArgument(value.Index(i).Interface(), t.Elem) 332 sliceStr = append(sliceStr, elemStr) 333 ok = ok && elemOk 334 } 335 336 str = "[" + strings.Join(sliceStr, " ") + "]" 337 } 338 339 case abi.IntTy, abi.UintTy: 340 if reflect.TypeOf(v) == reflect.TypeOf(big.NewInt(0)) { 341 var bigInt *big.Int 342 bigInt, ok = v.(*big.Int) 343 if ok { 344 str = bigInt.String() 345 } 346 } else if 2 <= reflect.TypeOf(v).Kind() && reflect.TypeOf(v).Kind() <= 11 { 347 // other integer types (int8,uint16,...) can be handled by fmt.Sprint(v) 348 ok = true 349 } 350 351 case abi.AddressTy: 352 if reflect.TypeOf(v) == reflect.TypeOf(common.Address{}) { 353 var ethAddr common.Address 354 ethAddr, ok = v.(common.Address) 355 if ok { 356 ioAddress, err := address.FromBytes(ethAddr.Bytes()) 357 if err == nil { 358 str = ioAddress.String() 359 } 360 } 361 } 362 363 case abi.BytesTy: 364 if reflect.TypeOf(v) == reflect.TypeOf([]byte{}) { 365 var bytes []byte 366 bytes, ok = v.([]byte) 367 if ok { 368 str = "0x" + hex.EncodeToString(bytes) 369 } 370 } 371 372 case abi.FixedBytesTy, abi.FunctionTy: 373 if reflect.TypeOf(v).Kind() == reflect.Array && reflect.TypeOf(v).Elem() == reflect.TypeOf(byte(0)) { 374 bytesValue := reflect.ValueOf(v) 375 byteSlice := reflect.MakeSlice(reflect.TypeOf([]byte{}), bytesValue.Len(), bytesValue.Len()) 376 reflect.Copy(byteSlice, bytesValue) 377 378 str = "0x" + hex.EncodeToString(byteSlice.Bytes()) 379 ok = true 380 } 381 } 382 383 return str, ok 384 }