Skip to content

Commit 1f266e0

Browse files
committed
fixes issue #52, support complex param input and analyze tx with such inputs, add better error message to ethersacn abi api query
1 parent 398b706 commit 1f266e0

11 files changed

+423
-180
lines changed

Diff for: cmd/contract.go

+74-23
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io/ioutil"
77
"math/big"
8+
"os"
89
"strings"
910

1011
"github.com/ethereum/go-ethereum/accounts/abi"
@@ -245,35 +246,85 @@ func handleReadOneFunctionOnContract(reader *reader.EthReader, a *abi.ABI, atBlo
245246
fmt.Printf("Output:\n")
246247
result := contractReadResult{}
247248
for i, output := range method.Outputs {
248-
values := analyzer.ParamAsJarvisValues(output.Type, ps[i])
249-
valueStrs := []string{}
250-
for _, v := range values {
251-
valueStrs = append(valueStrs, v.Value)
252-
}
253-
result = append(result, returnVariable{
254-
Name: output.Name,
255-
Values: valueStrs,
256-
HumanValues: VerboseValues(values),
257-
})
258-
259-
fmt.Printf(
260-
"%d. %s (%s): %s\n",
261-
i+1,
262-
output.Name,
263-
output.Type.String(),
264-
indent(8, VerboseValues(values)),
265-
)
249+
oneOutputParamResult := analyzer.ParamAsJarvisParamResult(output.Name, output.Type, ps[i])
250+
oneVerboseParamResult := convertToVerboseParamResult(oneOutputParamResult)
251+
result = append(result, oneVerboseParamResult)
252+
253+
// returnVariable{
254+
// Name: output.Name,
255+
// Values: valueStrs,
256+
// HumanValues: VerboseValues(values),
257+
// })
258+
259+
fmt.Printf("%d. ", i+1)
260+
PrintVerboseParamResultToWriter(os.Stdout, oneOutputParamResult, 0, true)
266261
}
267262
return result, nil
268263
}
269264

270-
type returnVariable struct {
271-
Name string `json:"name"`
272-
Values []string `json:"values"`
273-
HumanValues []string `json:"human_values"`
265+
func convertToVerboseParamResult(oneOutputParamResult ParamResult) verboseParamResult {
266+
result := verboseParamResult{
267+
Name: oneOutputParamResult.Name,
268+
Type: oneOutputParamResult.Type,
269+
}
270+
271+
if oneOutputParamResult.Values != nil {
272+
result.Values = []string{}
273+
for _, v := range oneOutputParamResult.Values {
274+
result.Values = append(result.Values, v.Value)
275+
}
276+
result.HumanValues = VerboseValues(oneOutputParamResult.Values)
277+
}
278+
279+
if oneOutputParamResult.Tuples != nil {
280+
result.Tuples = []verboseTupleParamResult{}
281+
for _, t := range oneOutputParamResult.Tuples {
282+
result.Tuples = append(result.Tuples, convertToVerboseTupleParamResult(t))
283+
}
284+
}
285+
286+
if oneOutputParamResult.Arrays != nil {
287+
result.Arrays = []verboseParamResult{}
288+
for _, a := range oneOutputParamResult.Arrays {
289+
result.Arrays = append(result.Arrays, convertToVerboseParamResult(a))
290+
}
291+
}
292+
293+
return result
294+
}
295+
296+
func convertToVerboseTupleParamResult(oneTupleParamResult TupleParamResult) verboseTupleParamResult {
297+
result := verboseTupleParamResult{
298+
Name: oneTupleParamResult.Name,
299+
Type: oneTupleParamResult.Type,
300+
}
301+
302+
if oneTupleParamResult.Values != nil {
303+
result.Values = []verboseParamResult{}
304+
for _, v := range oneTupleParamResult.Values {
305+
result.Values = append(result.Values, convertToVerboseParamResult(v))
306+
}
307+
}
308+
309+
return result
310+
}
311+
312+
type verboseParamResult struct {
313+
Name string `json:"name"`
314+
Type string `json:"type"`
315+
Values []string `json:"values"`
316+
Tuples []verboseTupleParamResult `json:"tuples"`
317+
Arrays []verboseParamResult `json:"arrays"`
318+
HumanValues []string `json:"human_values"`
319+
}
320+
321+
type verboseTupleParamResult struct {
322+
Name string `json:"name"`
323+
Type string `json:"type"`
324+
Values []verboseParamResult `json:"values"`
274325
}
275326

276-
type contractReadResult []returnVariable
327+
type contractReadResult []verboseParamResult
277328

278329
type contractReadResultJSON struct {
279330
Result contractReadResult `json:"result"`

Diff for: cmd/util/pre_process.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func CommonTxPreprocess(cmd *cobra.Command, args []string) (err error) {
9797
} else if config.CustomABI != "" {
9898
a, err = util.ReadCustomABI(config.To, config.CustomABI, config.Network())
9999
if err != nil {
100-
return fmt.Errorf("reading cusom abi failed: %w", err)
100+
return fmt.Errorf("reading custom abi failed: %w", err)
101101
}
102102
}
103103
}

Diff for: cmd/util/prompt_util.go

+22-24
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,16 @@ func PromptArray(input abi.Argument, prefill string, network Network) (interface
160160
if err != nil {
161161
return nil, err
162162
}
163-
if len(inpStr) < 2 || inpStr[0] != '[' || inpStr[len(inpStr)-1] != ']' {
164-
return nil, fmt.Errorf("input must be wrapped by []")
165-
}
166-
arrayContent := strings.Trim(inpStr[1:len(inpStr)-1], " ")
167-
paramsStr := []string{}
168-
for _, p := range strings.Split(arrayContent, ",") {
169-
if strings.Trim(p, " ") != "" {
170-
paramsStr = append(paramsStr, p)
171-
}
163+
164+
paramsStr, err := util.SplitArrayOrTupleStringInput(inpStr)
165+
if err != nil {
166+
return nil, err
172167
}
173168

174169
switch input.Type.Elem.T {
175170
case abi.StringTy: // variable arrays are written at the end of the return bytes
176171
result := []string{}
177-
if len(arrayContent) == 0 {
172+
if len(paramsStr) == 0 {
178173
return result, nil
179174
}
180175
for _, p := range paramsStr {
@@ -187,7 +182,7 @@ func PromptArray(input abi.Argument, prefill string, network Network) (interface
187182
return result, nil
188183
case abi.IntTy, abi.UintTy:
189184
result := []*big.Int{}
190-
if len(arrayContent) == 0 {
185+
if len(paramsStr) == 0 {
191186
return result, nil
192187
}
193188
for _, p := range paramsStr {
@@ -200,7 +195,7 @@ func PromptArray(input abi.Argument, prefill string, network Network) (interface
200195
return result, nil
201196
case abi.BoolTy:
202197
result := []bool{}
203-
if len(arrayContent) == 0 {
198+
if len(paramsStr) == 0 {
204199
return result, nil
205200
}
206201
for _, p := range paramsStr {
@@ -213,7 +208,7 @@ func PromptArray(input abi.Argument, prefill string, network Network) (interface
213208
return result, nil
214209
case abi.AddressTy:
215210
result := []common.Address{}
216-
if len(arrayContent) == 0 {
211+
if len(paramsStr) == 0 {
217212
return result, nil
218213
}
219214
for _, p := range paramsStr {
@@ -226,7 +221,7 @@ func PromptArray(input abi.Argument, prefill string, network Network) (interface
226221
return result, nil
227222
case abi.HashTy:
228223
result := []common.Hash{}
229-
if len(arrayContent) == 0 {
224+
if len(paramsStr) == 0 {
230225
return result, nil
231226
}
232227
for _, p := range paramsStr {
@@ -264,7 +259,7 @@ func PromptArray(input abi.Argument, prefill string, network Network) (interface
264259
result = reflect.Append(result, reflect.ValueOf(converted))
265260
}
266261

267-
return result, nil
262+
return result.Interface(), nil
268263
default:
269264
return nil, fmt.Errorf(
270265
"not supported array of type: %s - %x",
@@ -354,6 +349,11 @@ func PromptTxData(
354349
if err != nil {
355350
return []byte{}, err
356351
}
352+
353+
for _, param := range params {
354+
DebugPrintf("param: %+v\n", param)
355+
}
356+
357357
if method.Type == abi.Constructor {
358358
return method.Inputs.Pack(params...)
359359
}
@@ -443,7 +443,7 @@ func PromptFunctionCallData(
443443
fmt.Printf("Method: %s\n", methodName)
444444
inputs := method.Inputs
445445
if prefillMode && len(inputs) != len(prefills) {
446-
return nil, nil, fmt.Errorf("You must specify enough params in prefilled mode")
446+
return nil, nil, fmt.Errorf("you must specify enough params in prefilled mode")
447447
}
448448
fmt.Printf("Input:\n")
449449
params = []interface{}{}
@@ -462,21 +462,19 @@ func PromptFunctionCallData(
462462
continue
463463
}
464464

465-
fmt.Printf(
466-
" You entered: %s\n",
467-
indent(8, VerboseValues(analyzer.ParamAsJarvisValues(input.Type, inputParam))),
468-
)
465+
fmt.Printf(" You entered:\n")
466+
PrintVerboseParamResultToWriter(os.Stdout, analyzer.ParamAsJarvisParamResult(input.Name, input.Type, inputParam), 2, true)
467+
fmt.Printf("\n")
469468
} else {
470469
inputParam, err = PromptParam(false, input, prefills[pi], network) // not interactive prompt
471470
if err != nil {
472471
fmt.Printf("Your input is not valid: %s\n", err)
473472
continue
474473
}
475474

476-
fmt.Printf(
477-
": %s\n",
478-
indent(8, VerboseValues(analyzer.ParamAsJarvisValues(input.Type, inputParam))),
479-
)
475+
fmt.Printf(":\n")
476+
PrintVerboseParamResultToWriter(os.Stdout, analyzer.ParamAsJarvisParamResult(input.Name, input.Type, inputParam), 2, true)
477+
fmt.Printf("\n")
480478
}
481479
params = append(params, inputParam)
482480
pi++

Diff for: cmd/util/util.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -103,28 +103,28 @@ func AnalyzeAndShowMsigTxInfo(
103103
fmt.Printf(
104104
"From: %s\nSending: %s %s (%s)\nTo: %s\n",
105105
VerboseAddress(util.GetJarvisAddress(multisigContract.Address, network)),
106-
InfoColor(fmt.Sprintf("%f", StringToFloat(funcCall.Params[1].Value[0].Value, decimal))),
106+
InfoColor(fmt.Sprintf("%f", StringToFloat(funcCall.Params[1].Values[0].Value, decimal))),
107107
InfoColor(symbol),
108108
address,
109-
VerboseAddress(util.GetJarvisAddress(funcCall.Params[0].Value[0].Value, network)),
109+
VerboseAddress(util.GetJarvisAddress(funcCall.Params[0].Values[0].Value, network)),
110110
)
111111
case "transferFrom":
112112
isStandardERC20Call = true
113113

114114
fmt.Printf(
115115
"From: %s\nSending: %f %s (%s)\nTo: %s\n",
116-
VerboseAddress(util.GetJarvisAddress(funcCall.Params[0].Value[0].Value, network)),
117-
StringToFloat(funcCall.Params[2].Value[0].Value, decimal),
116+
VerboseAddress(util.GetJarvisAddress(funcCall.Params[0].Values[0].Value, network)),
117+
StringToFloat(funcCall.Params[2].Values[0].Value, decimal),
118118
symbol,
119119
address,
120-
VerboseAddress(util.GetJarvisAddress(funcCall.Params[1].Value[0].Value, network)),
120+
VerboseAddress(util.GetJarvisAddress(funcCall.Params[1].Values[0].Value, network)),
121121
)
122122
case "approve":
123123
isStandardERC20Call = true
124124
fmt.Printf(
125125
"Approving %s to spend upto: %f %s (%s) from the multisig\n",
126-
VerboseAddress(util.GetJarvisAddress(funcCall.Params[0].Value[0].Value, network)),
127-
StringToFloat(funcCall.Params[1].Value[0].Value, decimal),
126+
VerboseAddress(util.GetJarvisAddress(funcCall.Params[0].Values[0].Value, network)),
127+
StringToFloat(funcCall.Params[1].Values[0].Value, decimal),
128128
symbol,
129129
address,
130130
)

Diff for: common/ethereum_data.go

+45-6
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package common
33
import (
44
"encoding/json"
55
"fmt"
6-
"io/ioutil"
76
"math/big"
7+
"os"
88
)
99

1010
type Address struct {
@@ -28,11 +28,49 @@ type FunctionCall struct {
2828
Error string
2929
}
3030

31+
// ParamResult is the general struct that aims to be able to store all of the information of a parameter
32+
// 1. Para meter is an arbitrary type such as string, int, uint, bool, address, hash, bytes, fixed bytes
33+
// ParamResult{
34+
// Name: "param1", // in case it is an element of an array, name = array_name[index]
35+
// Type: "string", // or "int", "uint", "bool", "address", "hash", "bytes", "fixed bytes"
36+
// Values: [1]Value{}, // where this has only one value
37+
// }
38+
// 2. Parameter is a slice or an array of arbitrary types
39+
// ParamResult{
40+
// Name: "param1",
41+
// Type: "string[]", // or "int[]", "uint[]", "bool[]", "address[]", "hash[]", "bytes[]", "fixed bytes[]"
42+
// Values: [n]Value{}, // where this has multiple values
43+
// }
44+
// 3. Parameter is a tuple
45+
// ParamResult{
46+
// Name: "param1",
47+
// Type: "tuple",
48+
// Tuples: [1][]ParamResult{}, // where this has
49+
// }
50+
// 4. Parameter is a slice or an array of tuples
51+
// ParamResult{
52+
// Name: "param1",
53+
// Type: "tuple[]", // or "tuple[2]", "tuple[2][3]"
54+
// Tuples: [n][]ParamResult{}, // where this has multiple tuples, []ParamResult represents a tuple
55+
// }
56+
// 5. Parameter is a slice or an array of another slice/array
57+
// ParamResult{
58+
// Name: "param1",
59+
// Type: "string[][]", // or "int[][]", "uint[][]", "bool[][]", "address[][]", "hash[][]", "bytes[][]", "fixed bytes[][]"
60+
// Arrays: [n]ParamResult{}, // where this has multiple arrays, []ParamResult represents an array
61+
// }
3162
type ParamResult struct {
32-
Name string
33-
Type string
34-
Value []Value
35-
Tuple []ParamResult
63+
Name string
64+
Type string
65+
Values []Value // Values stores the values of the parameters, in case the param is an array of arbitrary types, it will have more than one value
66+
Tuples []TupleParamResult // []ParamResult represents a tuple, this has more than one tuple if the param is a slice or an array of tuples
67+
Arrays []ParamResult // Arrays stores the values of the parameters, in case the param is a slice or an array of another slice/array, it will have more than one value
68+
}
69+
70+
type TupleParamResult struct {
71+
Name string
72+
Type string
73+
Values []ParamResult
3674
}
3775

3876
type TopicResult struct {
@@ -50,7 +88,8 @@ type TxResults map[string]*TxResult
5088

5189
func (tr *TxResults) Write(filepath string) {
5290
data, _ := json.MarshalIndent(tr, "", " ")
53-
err := ioutil.WriteFile(filepath, data, 0644)
91+
92+
err := os.WriteFile(filepath, data, 0644)
5493
if err != nil {
5594
fmt.Printf("Writing to json file failed: %s\n", err)
5695
}

0 commit comments

Comments
 (0)