github.com/ava-labs/subnet-evm@v0.6.4/accounts/abi/method.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  	"fmt"
    31  	"strings"
    32  
    33  	"github.com/ethereum/go-ethereum/crypto"
    34  )
    35  
    36  // FunctionType represents different types of functions a contract might have.
    37  type FunctionType int
    38  
    39  const (
    40  	// Constructor represents the constructor of the contract.
    41  	// The constructor function is called while deploying a contract.
    42  	Constructor FunctionType = iota
    43  	// Fallback represents the fallback function.
    44  	// This function is executed if no other function matches the given function
    45  	// signature and no receive function is specified.
    46  	Fallback
    47  	// Receive represents the receive function.
    48  	// This function is executed on plain Ether transfers.
    49  	Receive
    50  	// Function represents a normal function.
    51  	Function
    52  )
    53  
    54  // Method represents a callable given a `Name` and whether the method is a constant.
    55  // If the method is `Const` no transaction needs to be created for this
    56  // particular Method call. It can easily be simulated using a local VM.
    57  // For example a `Balance()` method only needs to retrieve something
    58  // from the storage and therefore requires no Tx to be sent to the
    59  // network. A method such as `Transact` does require a Tx and thus will
    60  // be flagged `false`.
    61  // Input specifies the required input parameters for this gives method.
    62  type Method struct {
    63  	// Name is the method name used for internal representation. It's derived from
    64  	// the raw name and a suffix will be added in the case of a function overload.
    65  	//
    66  	// e.g.
    67  	// These are two functions that have the same name:
    68  	// * foo(int,int)
    69  	// * foo(uint,uint)
    70  	// The method name of the first one will be resolved as foo while the second one
    71  	// will be resolved as foo0.
    72  	Name    string
    73  	RawName string // RawName is the raw method name parsed from ABI
    74  
    75  	// Type indicates whether the method is a
    76  	// special fallback introduced in solidity v0.6.0
    77  	Type FunctionType
    78  
    79  	// StateMutability indicates the mutability state of method,
    80  	// the default value is nonpayable. It can be empty if the abi
    81  	// is generated by legacy compiler.
    82  	StateMutability string
    83  
    84  	// Legacy indicators generated by compiler before v0.6.0
    85  	Constant bool
    86  	Payable  bool
    87  
    88  	Inputs  Arguments
    89  	Outputs Arguments
    90  	str     string
    91  	// Sig returns the methods string signature according to the ABI spec.
    92  	// e.g.		function foo(uint32 a, int b) = "foo(uint32,int256)"
    93  	// Please note that "int" is substitute for its canonical representation "int256"
    94  	Sig string
    95  	// ID returns the canonical representation of the method's signature used by the
    96  	// abi definition to identify method names and types.
    97  	ID []byte
    98  }
    99  
   100  // NewMethod creates a new Method.
   101  // A method should always be created using NewMethod.
   102  // It also precomputes the sig representation and the string representation
   103  // of the method.
   104  func NewMethod(name string, rawName string, funType FunctionType, mutability string, isConst, isPayable bool, inputs Arguments, outputs Arguments) Method {
   105  	var (
   106  		types       = make([]string, len(inputs))
   107  		inputNames  = make([]string, len(inputs))
   108  		outputNames = make([]string, len(outputs))
   109  	)
   110  	for i, input := range inputs {
   111  		inputNames[i] = fmt.Sprintf("%v %v", input.Type, input.Name)
   112  		types[i] = input.Type.String()
   113  	}
   114  	for i, output := range outputs {
   115  		outputNames[i] = output.Type.String()
   116  		if len(output.Name) > 0 {
   117  			outputNames[i] += fmt.Sprintf(" %v", output.Name)
   118  		}
   119  	}
   120  	// calculate the signature and method id. Note only function
   121  	// has meaningful signature and id.
   122  	var (
   123  		sig string
   124  		id  []byte
   125  	)
   126  	if funType == Function {
   127  		sig = fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
   128  		id = crypto.Keccak256([]byte(sig))[:4]
   129  	}
   130  	// Extract meaningful state mutability of solidity method.
   131  	// If it's default value, never print it.
   132  	state := mutability
   133  	if state == "nonpayable" {
   134  		state = ""
   135  	}
   136  	if state != "" {
   137  		state = state + " "
   138  	}
   139  	identity := fmt.Sprintf("function %v", rawName)
   140  	switch funType {
   141  	case Fallback:
   142  		identity = "fallback"
   143  	case Receive:
   144  		identity = "receive"
   145  	case Constructor:
   146  		identity = "constructor"
   147  	}
   148  	str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", "))
   149  
   150  	return Method{
   151  		Name:            name,
   152  		RawName:         rawName,
   153  		Type:            funType,
   154  		StateMutability: mutability,
   155  		Constant:        isConst,
   156  		Payable:         isPayable,
   157  		Inputs:          inputs,
   158  		Outputs:         outputs,
   159  		str:             str,
   160  		Sig:             sig,
   161  		ID:              id,
   162  	}
   163  }
   164  
   165  func (method Method) String() string {
   166  	return method.str
   167  }
   168  
   169  // IsConstant returns the indicator whether the method is read-only.
   170  func (method Method) IsConstant() bool {
   171  	return method.StateMutability == "view" || method.StateMutability == "pure" || method.Constant
   172  }
   173  
   174  // IsPayable returns the indicator whether the method can process
   175  // plain ether transfers.
   176  func (method Method) IsPayable() bool {
   177  	return method.StateMutability == "payable" || method.Payable
   178  }