Skip to content

Commit b0a3f70

Browse files
authored
Merge branch 'master' into sync/v1.16.3-merge
2 parents 0b974de + 9b4ae32 commit b0a3f70

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed

accounts/abi/argument.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,40 @@ func (arguments Arguments) UnpackValuesAsStrings(data []byte) ([]interface{}, er
275275
return retval, nil
276276
}
277277

278+
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
279+
// without supplying a struct to unpack into. Instead, this method returns a list containing the
280+
// values converted to strings. An atomic argument will be a list with one element.
281+
func (arguments Arguments) UnpackValuesAsStrings(data []byte) ([]interface{}, error) {
282+
nonIndexedArgs := arguments.NonIndexed()
283+
retval := make([]interface{}, 0, len(nonIndexedArgs))
284+
virtualArgs := 0
285+
for index, arg := range nonIndexedArgs {
286+
marshalledValue, err := toString((index+virtualArgs)*32, arg.Type, data)
287+
if err != nil {
288+
return nil, err
289+
}
290+
if arg.Type.T == ArrayTy && !isDynamicType(arg.Type) {
291+
// If we have a static array, like [3]uint256, these are coded as
292+
// just like uint256,uint256,uint256.
293+
// This means that we need to add two 'virtual' arguments when
294+
// we count the index from now on.
295+
//
296+
// Array values nested multiple levels deep are also encoded inline:
297+
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
298+
//
299+
// Calculate the full array size to get the correct offset for the next argument.
300+
// Decrement it by 1, as the normal index increment is still applied.
301+
virtualArgs += getTypeSize(arg.Type)/32 - 1
302+
} else if arg.Type.T == TupleTy && !isDynamicType(arg.Type) {
303+
// If we have a static tuple, like (uint256, bool, uint256), these are
304+
// coded as just like uint256,bool,uint256
305+
virtualArgs += getTypeSize(arg.Type)/32 - 1
306+
}
307+
retval = append(retval, marshalledValue)
308+
}
309+
return retval, nil
310+
}
311+
278312
// PackValues performs the operation Go format -> Hexdata.
279313
// It is the semantic opposite of UnpackValues.
280314
func (arguments Arguments) PackValues(args []any) ([]byte, error) {

accounts/abi/type.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,166 @@ func NewTypeAsString(t string, internalType string, components []ArgumentMarshal
390390
return
391391
}
392392

393+
// NewTypeAsString creates a new reflection type of abi type given in t.
394+
func NewTypeAsString(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) {
395+
// check that array brackets are equal if they exist
396+
if strings.Count(t, "[") != strings.Count(t, "]") {
397+
return Type{}, errors.New("invalid arg type in abi")
398+
}
399+
typ.stringKind = t
400+
401+
// if there are brackets, get ready to go into slice/array mode and
402+
// recursively create the type
403+
if strings.Count(t, "[") != 0 {
404+
// Note internalType can be empty here.
405+
subInternal := internalType
406+
if i := strings.LastIndex(internalType, "["); i != -1 {
407+
subInternal = subInternal[:i]
408+
}
409+
// recursively embed the type
410+
i := strings.LastIndex(t, "[")
411+
embeddedType, err := NewTypeAsString(t[:i], subInternal, components)
412+
if err != nil {
413+
return Type{}, err
414+
}
415+
// grab the last cell and create a type from there
416+
sliced := t[i:]
417+
// grab the slice size with regexp
418+
re := regexp.MustCompile("[0-9]+")
419+
intz := re.FindAllString(sliced, -1)
420+
421+
if len(intz) == 0 {
422+
// is a slice
423+
typ.T = SliceTy
424+
typ.Elem = &embeddedType
425+
typ.stringKind = embeddedType.stringKind + sliced
426+
} else if len(intz) == 1 {
427+
// is an array
428+
typ.T = ArrayTy
429+
typ.Elem = &embeddedType
430+
typ.Size, err = strconv.Atoi(intz[0])
431+
if err != nil {
432+
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
433+
}
434+
typ.stringKind = embeddedType.stringKind + sliced
435+
} else {
436+
return Type{}, errors.New("invalid formatting of array type")
437+
}
438+
return typ, err
439+
}
440+
// parse the type and size of the abi-type.
441+
matches := typeRegex.FindAllStringSubmatch(t, -1)
442+
if len(matches) == 0 {
443+
return Type{}, fmt.Errorf("invalid type '%v'", t)
444+
}
445+
parsedType := matches[0]
446+
447+
// varSize is the size of the variable
448+
var varSize int
449+
if len(parsedType[3]) > 0 {
450+
var err error
451+
varSize, err = strconv.Atoi(parsedType[2])
452+
if err != nil {
453+
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
454+
}
455+
} else {
456+
if parsedType[0] == "uint" || parsedType[0] == "int" {
457+
// this should fail because it means that there's something wrong with
458+
// the abi type (the compiler should always format it to the size...always)
459+
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
460+
}
461+
}
462+
// varType is the parsed abi type
463+
switch varType := parsedType[1]; varType {
464+
case "int":
465+
typ.Size = varSize
466+
typ.T = IntTy
467+
case "uint":
468+
typ.Size = varSize
469+
typ.T = UintTy
470+
case "bool":
471+
typ.T = BoolTy
472+
case "address":
473+
typ.Size = 20
474+
typ.T = AddressTy
475+
case "string":
476+
typ.T = StringTy
477+
case "bytes":
478+
if varSize == 0 {
479+
typ.T = BytesTy
480+
} else {
481+
if varSize > 32 {
482+
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
483+
}
484+
typ.T = FixedBytesTy
485+
typ.Size = varSize
486+
}
487+
case "tuple":
488+
var (
489+
fields []reflect.StructField
490+
elems []*Type
491+
names []string
492+
expression string // canonical parameter expression
493+
used = make(map[string]bool)
494+
)
495+
expression += "("
496+
for idx, c := range components {
497+
cType, err := NewTypeAsString(c.Type, c.InternalType, c.Components)
498+
if err != nil {
499+
return Type{}, err
500+
}
501+
name := ToCamelCase(c.Name)
502+
if name == "" {
503+
return Type{}, errors.New("abi: purely anonymous or underscored field is not supported")
504+
}
505+
fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] })
506+
if err != nil {
507+
return Type{}, err
508+
}
509+
used[fieldName] = true
510+
if !isValidFieldName(fieldName) {
511+
return Type{}, fmt.Errorf("field %d has invalid name", idx)
512+
}
513+
fields = append(fields, reflect.StructField{
514+
Name: fieldName, // reflect.StructOf will panic for any exported field.
515+
Type: cType.GetTypeAsString(),
516+
Tag: reflect.StructTag("json:\"" + c.Name + "\""),
517+
})
518+
elems = append(elems, &cType)
519+
names = append(names, c.Name)
520+
expression += cType.stringKind
521+
if idx != len(components)-1 {
522+
expression += ","
523+
}
524+
}
525+
expression += ")"
526+
527+
typ.TupleType = reflect.StructOf(fields)
528+
typ.TupleElems = elems
529+
typ.TupleRawNames = names
530+
typ.T = TupleTy
531+
typ.stringKind = expression
532+
533+
const structPrefix = "struct "
534+
// After solidity 0.5.10, a new field of abi "internalType"
535+
// is introduced. From that we can obtain the struct name
536+
// user defined in the source code.
537+
if internalType != "" && strings.HasPrefix(internalType, structPrefix) {
538+
// Foo.Bar type definition is not allowed in golang,
539+
// convert the format to FooBar
540+
typ.TupleRawName = strings.ReplaceAll(internalType[len(structPrefix):], ".", "")
541+
}
542+
543+
case "function":
544+
typ.T = FunctionTy
545+
typ.Size = 24
546+
default:
547+
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
548+
}
549+
550+
return
551+
}
552+
393553
// GetType returns the reflection type of the ABI type.
394554
func (t Type) GetType() reflect.Type {
395555
switch t.T {
@@ -458,6 +618,42 @@ func (t Type) GetTypeAsString() reflect.Type {
458618
}
459619
}
460620

621+
// GetTypeAsString returns the reflection type of the ABI type (always string).
622+
func (t Type) GetTypeAsString() reflect.Type {
623+
switch t.T {
624+
case IntTy:
625+
return reflect.TypeOf("")
626+
case UintTy:
627+
return reflect.TypeOf("")
628+
case BoolTy:
629+
return reflect.TypeOf("")
630+
case StringTy:
631+
return reflect.TypeOf("")
632+
case SliceTy:
633+
return reflect.SliceOf(t.Elem.GetTypeAsString())
634+
case ArrayTy:
635+
return reflect.ArrayOf(t.Size, t.Elem.GetTypeAsString())
636+
case TupleTy:
637+
return t.TupleType
638+
case AddressTy:
639+
return reflect.TypeOf("")
640+
case FixedBytesTy:
641+
return reflect.TypeOf("")
642+
case BytesTy:
643+
return reflect.TypeOf("")
644+
case HashTy:
645+
// hashtype currently not used
646+
return reflect.TypeOf("")
647+
case FixedPointTy:
648+
// fixedpoint type currently not used
649+
return reflect.TypeOf("")
650+
case FunctionTy:
651+
return reflect.TypeOf("")
652+
default:
653+
panic("Invalid type")
654+
}
655+
}
656+
461657
// String implements Stringer.
462658
func (t Type) String() (out string) {
463659
return t.stringKind

ethclient/ethclient.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,13 @@ func RevertErrorData(err error) ([]byte, bool) {
711711
}
712712
}
713713
return nil, false
714+
715+
// SendRawTransaction injects a raw transaction into the pending pool for execution.
716+
//
717+
// If the transaction was a contract creation use the TransactionReceipt method to get the
718+
// contract address after the transaction has been mined.
719+
func (ec *Client) SendRawTransaction(ctx context.Context, rawTx string) error {
720+
return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", rawTx)
714721
}
715722

716723
func toBlockNumArg(number *big.Int) string {

0 commit comments

Comments
 (0)