github.com/ava-labs/subnet-evm@v0.6.4/accounts/abi/abi.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2015 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package abi
    28  
    29  import (
    30  	"bytes"
    31  	"encoding/json"
    32  	"errors"
    33  	"fmt"
    34  	"io"
    35  	"math/big"
    36  
    37  	"github.com/ethereum/go-ethereum/common"
    38  	"github.com/ethereum/go-ethereum/crypto"
    39  )
    40  
    41  // The ABI holds information about a contract's context and available
    42  // invokable methods. It will allow you to type check function calls and
    43  // packs data accordingly.
    44  type ABI struct {
    45  	Constructor Method
    46  	Methods     map[string]Method
    47  	Events      map[string]Event
    48  	Errors      map[string]Error
    49  
    50  	// Additional "special" functions introduced in solidity v0.6.0.
    51  	// It's separated from the original default fallback. Each contract
    52  	// can only define one fallback and receive function.
    53  	Fallback Method // Note it's also used to represent legacy fallback before v0.6.0
    54  	Receive  Method
    55  }
    56  
    57  // JSON returns a parsed ABI interface and error if it failed.
    58  func JSON(reader io.Reader) (ABI, error) {
    59  	dec := json.NewDecoder(reader)
    60  
    61  	var abi ABI
    62  	if err := dec.Decode(&abi); err != nil {
    63  		return ABI{}, err
    64  	}
    65  	return abi, nil
    66  }
    67  
    68  // Pack the given method name to conform the ABI. Method call's data
    69  // will consist of method_id, args0, arg1, ... argN. Method id consists
    70  // of 4 bytes and arguments are all 32 bytes.
    71  // Method ids are created from the first 4 bytes of the hash of the
    72  // methods string signature. (signature = baz(uint32,string32))
    73  func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
    74  	// Fetch the ABI of the requested method
    75  	if name == "" {
    76  		// constructor
    77  		arguments, err := abi.Constructor.Inputs.Pack(args...)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  		return arguments, nil
    82  	}
    83  	method, exist := abi.Methods[name]
    84  	if !exist {
    85  		return nil, fmt.Errorf("method '%s' not found", name)
    86  	}
    87  	arguments, err := method.Inputs.Pack(args...)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	// Pack up the method ID too if not a constructor and return
    92  	return append(method.ID, arguments...), nil
    93  }
    94  
    95  // PackEvent packs the given event name and arguments to conform the ABI.
    96  // Returns the topics for the event including the event signature (if non-anonymous event) and
    97  // hashes derived from indexed arguments and the packed data of non-indexed args according to
    98  // the event ABI specification.
    99  // The order of arguments must match the order of the event definition.
   100  // https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#indexed-event-encoding.
   101  // Note: PackEvent does not support array (fixed or dynamic-size) or struct types.
   102  func (abi ABI) PackEvent(name string, args ...interface{}) ([]common.Hash, []byte, error) {
   103  	event, exist := abi.Events[name]
   104  	if !exist {
   105  		return nil, nil, fmt.Errorf("event '%s' not found", name)
   106  	}
   107  	if len(args) != len(event.Inputs) {
   108  		return nil, nil, fmt.Errorf("event '%s' unexpected number of inputs %d", name, len(args))
   109  	}
   110  
   111  	var (
   112  		nonIndexedInputs = make([]interface{}, 0)
   113  		indexedInputs    = make([]interface{}, 0)
   114  		nonIndexedArgs   Arguments
   115  		indexedArgs      Arguments
   116  	)
   117  
   118  	for i, arg := range event.Inputs {
   119  		if arg.Indexed {
   120  			indexedArgs = append(indexedArgs, arg)
   121  			indexedInputs = append(indexedInputs, args[i])
   122  		} else {
   123  			nonIndexedArgs = append(nonIndexedArgs, arg)
   124  			nonIndexedInputs = append(nonIndexedInputs, args[i])
   125  		}
   126  	}
   127  
   128  	packedArguments, err := nonIndexedArgs.Pack(nonIndexedInputs...)
   129  	if err != nil {
   130  		return nil, nil, err
   131  	}
   132  	topics := make([]common.Hash, 0, len(indexedArgs)+1)
   133  	if !event.Anonymous {
   134  		topics = append(topics, event.ID)
   135  	}
   136  	indexedTopics, err := PackTopics(indexedInputs)
   137  	if err != nil {
   138  		return nil, nil, err
   139  	}
   140  
   141  	return append(topics, indexedTopics...), packedArguments, nil
   142  }
   143  
   144  // PackOutput packs the given [args] as the output of given method [name] to conform the ABI.
   145  // This does not include method ID.
   146  func (abi ABI) PackOutput(name string, args ...interface{}) ([]byte, error) {
   147  	// Fetch the ABI of the requested method
   148  	method, exist := abi.Methods[name]
   149  	if !exist {
   150  		return nil, fmt.Errorf("method '%s' not found", name)
   151  	}
   152  	arguments, err := method.Outputs.Pack(args...)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	return arguments, nil
   157  }
   158  
   159  // getInputs gets input arguments of the given [name] method.
   160  // useStrictMode indicates whether to check the input data length strictly.
   161  func (abi ABI) getInputs(name string, data []byte, useStrictMode bool) (Arguments, error) {
   162  	// since there can't be naming collisions with contracts and events,
   163  	// we need to decide whether we're calling a method or an event
   164  	var args Arguments
   165  	if method, ok := abi.Methods[name]; ok {
   166  		if useStrictMode && len(data)%32 != 0 {
   167  			return nil, fmt.Errorf("abi: improperly formatted input: %s - Bytes: [%+v]", string(data), data)
   168  		}
   169  		args = method.Inputs
   170  	}
   171  	if event, ok := abi.Events[name]; ok {
   172  		args = event.Inputs
   173  	}
   174  	if args == nil {
   175  		return nil, fmt.Errorf("abi: could not locate named method or event: %s", name)
   176  	}
   177  	return args, nil
   178  }
   179  
   180  // getArguments gets output arguments of the given [name] method.
   181  func (abi ABI) getArguments(name string, data []byte) (Arguments, error) {
   182  	// since there can't be naming collisions with contracts and events,
   183  	// we need to decide whether we're calling a method or an event
   184  	var args Arguments
   185  	if method, ok := abi.Methods[name]; ok {
   186  		if len(data)%32 != 0 {
   187  			return nil, fmt.Errorf("abi: improperly formatted output: %q - Bytes: %+v", data, data)
   188  		}
   189  		args = method.Outputs
   190  	}
   191  	if event, ok := abi.Events[name]; ok {
   192  		args = event.Inputs
   193  	}
   194  	if args == nil {
   195  		return nil, fmt.Errorf("abi: could not locate named method or event: %s", name)
   196  	}
   197  	return args, nil
   198  }
   199  
   200  // UnpackInput unpacks the input according to the ABI specification.
   201  // useStrictMode indicates whether to check the input data length strictly.
   202  // By default it was set to true. In order to support the general EVM tool compatibility this
   203  // should be set to false. This transition (true -> false) should be done with a network upgrade.
   204  func (abi ABI) UnpackInput(name string, data []byte, useStrictMode bool) ([]interface{}, error) {
   205  	args, err := abi.getInputs(name, data, useStrictMode)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	return args.Unpack(data)
   210  }
   211  
   212  // Unpack unpacks the output according to the abi specification.
   213  func (abi ABI) Unpack(name string, data []byte) ([]interface{}, error) {
   214  	args, err := abi.getArguments(name, data)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	return args.Unpack(data)
   219  }
   220  
   221  // UnpackInputIntoInterface unpacks the input in v according to the ABI specification.
   222  // It performs an additional copy. Please only use, if you want to unpack into a
   223  // structure that does not strictly conform to the ABI structure (e.g. has additional arguments)
   224  // useStrictMode indicates whether to check the input data length strictly.
   225  // By default it was set to true. In order to support the general EVM tool compatibility this
   226  // should be set to false. This transition (true -> false) should be done with a network upgrade.
   227  func (abi ABI) UnpackInputIntoInterface(v interface{}, name string, data []byte, useStrictMode bool) error {
   228  	args, err := abi.getInputs(name, data, useStrictMode)
   229  	if err != nil {
   230  		return err
   231  	}
   232  	unpacked, err := args.Unpack(data)
   233  	if err != nil {
   234  		return err
   235  	}
   236  	return args.Copy(v, unpacked)
   237  }
   238  
   239  // UnpackIntoInterface unpacks the output in v according to the abi specification.
   240  // It performs an additional copy. Please only use, if you want to unpack into a
   241  // structure that does not strictly conform to the abi structure (e.g. has additional arguments)
   242  func (abi ABI) UnpackIntoInterface(v interface{}, name string, data []byte) error {
   243  	args, err := abi.getArguments(name, data)
   244  	if err != nil {
   245  		return err
   246  	}
   247  	unpacked, err := args.Unpack(data)
   248  	if err != nil {
   249  		return err
   250  	}
   251  	return args.Copy(v, unpacked)
   252  }
   253  
   254  // UnpackIntoMap unpacks a log into the provided map[string]interface{}.
   255  func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) {
   256  	args, err := abi.getArguments(name, data)
   257  	if err != nil {
   258  		return err
   259  	}
   260  	return args.UnpackIntoMap(v, data)
   261  }
   262  
   263  // UnmarshalJSON implements json.Unmarshaler interface.
   264  func (abi *ABI) UnmarshalJSON(data []byte) error {
   265  	var fields []struct {
   266  		Type    string
   267  		Name    string
   268  		Inputs  []Argument
   269  		Outputs []Argument
   270  
   271  		// Status indicator which can be: "pure", "view",
   272  		// "nonpayable" or "payable".
   273  		StateMutability string
   274  
   275  		// Deprecated Status indicators, but removed in v0.6.0.
   276  		Constant bool // True if function is either pure or view
   277  		Payable  bool // True if function is payable
   278  
   279  		// Event relevant indicator represents the event is
   280  		// declared as anonymous.
   281  		Anonymous bool
   282  	}
   283  	if err := json.Unmarshal(data, &fields); err != nil {
   284  		return err
   285  	}
   286  	abi.Methods = make(map[string]Method)
   287  	abi.Events = make(map[string]Event)
   288  	abi.Errors = make(map[string]Error)
   289  	for _, field := range fields {
   290  		switch field.Type {
   291  		case "constructor":
   292  			abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.Payable, field.Inputs, nil)
   293  		case "function":
   294  			name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return ok })
   295  			abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constant, field.Payable, field.Inputs, field.Outputs)
   296  		case "fallback":
   297  			// New introduced function type in v0.6.0, check more detail
   298  			// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
   299  			if abi.HasFallback() {
   300  				return errors.New("only single fallback is allowed")
   301  			}
   302  			abi.Fallback = NewMethod("", "", Fallback, field.StateMutability, field.Constant, field.Payable, nil, nil)
   303  		case "receive":
   304  			// New introduced function type in v0.6.0, check more detail
   305  			// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
   306  			if abi.HasReceive() {
   307  				return errors.New("only single receive is allowed")
   308  			}
   309  			if field.StateMutability != "payable" {
   310  				return errors.New("the statemutability of receive can only be payable")
   311  			}
   312  			abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable, nil, nil)
   313  		case "event":
   314  			name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Events[s]; return ok })
   315  			abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs)
   316  		case "error":
   317  			// Errors cannot be overloaded or overridden but are inherited,
   318  			// no need to resolve the name conflict here.
   319  			abi.Errors[field.Name] = NewError(field.Name, field.Inputs)
   320  		default:
   321  			return fmt.Errorf("abi: could not recognize type %v of field %v", field.Type, field.Name)
   322  		}
   323  	}
   324  	return nil
   325  }
   326  
   327  // MethodById looks up a method by the 4-byte id,
   328  // returns nil if none found.
   329  func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
   330  	if len(sigdata) < 4 {
   331  		return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
   332  	}
   333  	for _, method := range abi.Methods {
   334  		if bytes.Equal(method.ID, sigdata[:4]) {
   335  			return &method, nil
   336  		}
   337  	}
   338  	return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
   339  }
   340  
   341  // EventByID looks an event up by its topic hash in the
   342  // ABI and returns nil if none found.
   343  func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
   344  	for _, event := range abi.Events {
   345  		if bytes.Equal(event.ID.Bytes(), topic.Bytes()) {
   346  			return &event, nil
   347  		}
   348  	}
   349  	return nil, fmt.Errorf("no event with id: %#x", topic.Hex())
   350  }
   351  
   352  // ErrorByID looks up an error by the 4-byte id,
   353  // returns nil if none found.
   354  func (abi *ABI) ErrorByID(sigdata [4]byte) (*Error, error) {
   355  	for _, errABI := range abi.Errors {
   356  		if bytes.Equal(errABI.ID[:4], sigdata[:]) {
   357  			return &errABI, nil
   358  		}
   359  	}
   360  	return nil, fmt.Errorf("no error with id: %#x", sigdata[:])
   361  }
   362  
   363  // HasFallback returns an indicator whether a fallback function is included.
   364  func (abi *ABI) HasFallback() bool {
   365  	return abi.Fallback.Type == Fallback
   366  }
   367  
   368  // HasReceive returns an indicator whether a receive function is included.
   369  func (abi *ABI) HasReceive() bool {
   370  	return abi.Receive.Type == Receive
   371  }
   372  
   373  // revertSelector is a special function selector for revert reason unpacking.
   374  var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
   375  
   376  // panicSelector is a special function selector for panic reason unpacking.
   377  var panicSelector = crypto.Keccak256([]byte("Panic(uint256)"))[:4]
   378  
   379  // panicReasons map is for readable panic codes
   380  // see this linkage for the deails
   381  // https://docs.soliditylang.org/en/v0.8.21/control-structures.html#panic-via-assert-and-error-via-require
   382  // the reason string list is copied from ether.js
   383  // https://github.com/ethers-io/ethers.js/blob/fa3a883ff7c88611ce766f58bdd4b8ac90814470/src.ts/abi/interface.ts#L207-L218
   384  var panicReasons = map[uint64]string{
   385  	0x00: "generic panic",
   386  	0x01: "assert(false)",
   387  	0x11: "arithmetic underflow or overflow",
   388  	0x12: "division or modulo by zero",
   389  	0x21: "enum overflow",
   390  	0x22: "invalid encoded storage byte array accessed",
   391  	0x31: "out-of-bounds array access; popping on an empty array",
   392  	0x32: "out-of-bounds access of an array or bytesN",
   393  	0x41: "out of memory",
   394  	0x51: "uninitialized function",
   395  }
   396  
   397  // UnpackRevert resolves the abi-encoded revert reason. According to the solidity
   398  // spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert,
   399  // the provided revert reason is abi-encoded as if it were a call to function
   400  // `Error(string)` or `Panic(uint256)`. So it's a special tool for it.
   401  func UnpackRevert(data []byte) (string, error) {
   402  	if len(data) < 4 {
   403  		return "", errors.New("invalid data for unpacking")
   404  	}
   405  	switch {
   406  	case bytes.Equal(data[:4], revertSelector):
   407  		typ, err := NewType("string", "", nil)
   408  		if err != nil {
   409  			return "", err
   410  		}
   411  		unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
   412  		if err != nil {
   413  			return "", err
   414  		}
   415  		return unpacked[0].(string), nil
   416  	case bytes.Equal(data[:4], panicSelector):
   417  		typ, err := NewType("uint256", "", nil)
   418  		if err != nil {
   419  			return "", err
   420  		}
   421  		unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
   422  		if err != nil {
   423  			return "", err
   424  		}
   425  		pCode := unpacked[0].(*big.Int)
   426  		// uint64 safety check for future
   427  		// but the code is not bigger than MAX(uint64) now
   428  		if pCode.IsUint64() {
   429  			if reason, ok := panicReasons[pCode.Uint64()]; ok {
   430  				return reason, nil
   431  			}
   432  		}
   433  		return fmt.Sprintf("unknown panic code: %#x", pCode), nil
   434  	default:
   435  		return "", errors.New("invalid data for unpacking")
   436  	}
   437  }