github.com/lmittmann/w3@v0.20.0/internal/abi/arguments.go (about)

     1  package abi
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/ethereum/go-ethereum/accounts/abi"
     9  	"github.com/lmittmann/w3/internal/crypto"
    10  )
    11  
    12  // Arguments represents a slice of [abi.Argument]'s.
    13  type Arguments []abi.Argument
    14  
    15  func (a Arguments) Signature() string {
    16  	if len(a) <= 0 {
    17  		return ""
    18  	}
    19  
    20  	fields := make([]string, len(a))
    21  	for i, arg := range a {
    22  		fields[i] = typeToString(&arg.Type)
    23  	}
    24  	return strings.Join(fields, ",")
    25  }
    26  
    27  func (a Arguments) SignatureWithName(name string) string {
    28  	return name + "(" + a.Signature() + ")"
    29  }
    30  
    31  // Encode ABI-encodes the given arguments args.
    32  func (a Arguments) Encode(args ...any) ([]byte, error) {
    33  	data, err := abi.Arguments(a).PackValues(args)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	return data, nil
    38  }
    39  
    40  // EncodeWithSelector ABI-encodes the given arguments args prepended by the
    41  // given selector.
    42  func (a Arguments) EncodeWithSelector(selector [4]byte, args ...any) ([]byte, error) {
    43  	data, err := a.Encode(args...)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	data = append(selector[:], data...)
    49  	return data, nil
    50  }
    51  
    52  // EncodeWithSignature ABI-encodes the given arguments args prepended by the
    53  // first 4 bytes of the hash of the given signature.
    54  func (a Arguments) EncodeWithSignature(signature string, args ...any) ([]byte, error) {
    55  	var selector [4]byte
    56  	copy(selector[:], crypto.Keccak256([]byte(signature))[:4])
    57  
    58  	return a.EncodeWithSelector(selector, args...)
    59  }
    60  
    61  // Decode ABI-decodes the given data to the given arguments args.
    62  func (a Arguments) Decode(data []byte, args ...any) error {
    63  	values, err := abi.Arguments(a).UnpackValues(data)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	for i, arg := range args {
    69  		// discard if arg is nil
    70  		if arg == nil {
    71  			continue
    72  		}
    73  
    74  		if err := Copy(arg, values[i]); err != nil {
    75  			return err
    76  		}
    77  	}
    78  	return nil
    79  }
    80  
    81  // typeToString returns the string representation of a [abi.Type].
    82  func typeToString(t *abi.Type) string {
    83  	switch t.T {
    84  	case abi.IntTy:
    85  		return "int" + strconv.Itoa(t.Size)
    86  	case abi.UintTy:
    87  		return "uint" + strconv.Itoa(t.Size)
    88  	case abi.BoolTy:
    89  		return "bool"
    90  	case abi.StringTy:
    91  		return "string"
    92  	case abi.SliceTy:
    93  		return typeToString(t.Elem) + "[]"
    94  	case abi.ArrayTy:
    95  		return typeToString(t.Elem) + "[" + strconv.Itoa(t.Size) + "]"
    96  	case abi.TupleTy:
    97  		fields := make([]string, len(t.TupleElems))
    98  		for i, elem := range t.TupleElems {
    99  			fields[i] = typeToString(elem)
   100  		}
   101  		return "(" + strings.Join(fields, ",") + ")"
   102  	case abi.AddressTy:
   103  		return "address"
   104  	case abi.FixedBytesTy:
   105  		return "bytes" + strconv.Itoa(t.Size)
   106  	case abi.BytesTy:
   107  		return "bytes"
   108  	case abi.HashTy:
   109  		return "hash"
   110  	default:
   111  		panic(fmt.Sprintf("unsupported type %v", t))
   112  	}
   113  }