github.com/amazechain/amc@v0.1.3/internal/avm/abi/method.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The AmazeChain library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package abi
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  
    23  	"github.com/amazechain/amc/common/crypto"
    24  )
    25  
    26  // FunctionType represents different types of functions a contract might have.
    27  type FunctionType int
    28  
    29  const (
    30  	// Constructor represents the constructor of the contract.
    31  	// The constructor function is called while deploying a contract.
    32  	Constructor FunctionType = iota
    33  	// Fallback represents the fallback function.
    34  	// This function is executed if no other function matches the given function
    35  	// signature and no receive function is specified.
    36  	Fallback
    37  	// Receive represents the receive function.
    38  	// This function is executed on plain Ether transfers.
    39  	Receive
    40  	// Function represents a normal function.
    41  	Function
    42  )
    43  
    44  // Method represents a callable given a `Name` and whether the method is a constant.
    45  // If the method is `Const` no transaction needs to be created for this
    46  // particular Method call. It can easily be simulated using a local VM.
    47  // For example a `Balance()` method only needs to retrieve something
    48  // from the storage and therefore requires no Tx to be sent to the
    49  // network. A method such as `Transact` does require a Tx and thus will
    50  // be flagged `false`.
    51  // Input specifies the required input parameters for this gives method.
    52  type Method struct {
    53  	// Name is the method name used for internal representation. It's derived from
    54  	// the raw name and a suffix will be added in the case of a function overload.
    55  	//
    56  	// e.g.
    57  	// These are two functions that have the same name:
    58  	// * foo(int,int)
    59  	// * foo(uint,uint)
    60  	// The method name of the first one will be resolved as foo while the second one
    61  	// will be resolved as foo0.
    62  	Name    string
    63  	RawName string // RawName is the raw method name parsed from ABI
    64  
    65  	// Type indicates whether the method is a
    66  	// special fallback introduced in solidity v0.6.0
    67  	Type FunctionType
    68  
    69  	// StateMutability indicates the mutability state of method,
    70  	// the default value is nonpayable. It can be empty if the abi
    71  	// is generated by legacy compiler.
    72  	StateMutability string
    73  
    74  	// Legacy indicators generated by compiler before v0.6.0
    75  	Constant bool
    76  	Payable  bool
    77  
    78  	Inputs  Arguments
    79  	Outputs Arguments
    80  	str     string
    81  	// Sig returns the methods string signature according to the ABI spec.
    82  	// e.g.		function foo(uint32 a, int b) = "foo(uint32,int256)"
    83  	// Please note that "int" is substitute for its canonical representation "int256"
    84  	Sig string
    85  	// ID returns the canonical representation of the method's signature used by the
    86  	// abi definition to identify method names and types.
    87  	ID []byte
    88  }
    89  
    90  // NewMethod creates a new Method.
    91  // A method should always be created using NewMethod.
    92  // It also precomputes the sig representation and the string representation
    93  // of the method.
    94  func NewMethod(name string, rawName string, funType FunctionType, mutability string, isConst, isPayable bool, inputs Arguments, outputs Arguments) Method {
    95  	var (
    96  		types       = make([]string, len(inputs))
    97  		inputNames  = make([]string, len(inputs))
    98  		outputNames = make([]string, len(outputs))
    99  	)
   100  	for i, input := range inputs {
   101  		inputNames[i] = fmt.Sprintf("%v %v", input.Type, input.Name)
   102  		types[i] = input.Type.String()
   103  	}
   104  	for i, output := range outputs {
   105  		outputNames[i] = output.Type.String()
   106  		if len(output.Name) > 0 {
   107  			outputNames[i] += fmt.Sprintf(" %v", output.Name)
   108  		}
   109  	}
   110  	// calculate the signature and method id. Note only function
   111  	// has meaningful signature and id.
   112  	var (
   113  		sig string
   114  		id  []byte
   115  	)
   116  	if funType == Function {
   117  		sig = fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
   118  		id = crypto.Keccak256([]byte(sig))[:4]
   119  	}
   120  	// Extract meaningful state mutability of solidity method.
   121  	// If it's default value, never print it.
   122  	state := mutability
   123  	if state == "nonpayable" {
   124  		state = ""
   125  	}
   126  	if state != "" {
   127  		state = state + " "
   128  	}
   129  	identity := fmt.Sprintf("function %v", rawName)
   130  	if funType == Fallback {
   131  		identity = "fallback"
   132  	} else if funType == Receive {
   133  		identity = "receive"
   134  	} else if funType == Constructor {
   135  		identity = "constructor"
   136  	}
   137  	str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", "))
   138  
   139  	return Method{
   140  		Name:            name,
   141  		RawName:         rawName,
   142  		Type:            funType,
   143  		StateMutability: mutability,
   144  		Constant:        isConst,
   145  		Payable:         isPayable,
   146  		Inputs:          inputs,
   147  		Outputs:         outputs,
   148  		str:             str,
   149  		Sig:             sig,
   150  		ID:              id,
   151  	}
   152  }
   153  
   154  func (method Method) String() string {
   155  	return method.str
   156  }
   157  
   158  // IsConstant returns the indicator whether the method is read-only.
   159  func (method Method) IsConstant() bool {
   160  	return method.StateMutability == "view" || method.StateMutability == "pure" || method.Constant
   161  }
   162  
   163  // IsPayable returns the indicator whether the method can process
   164  // plain ether transfers.
   165  func (method Method) IsPayable() bool {
   166  	return method.StateMutability == "payable" || method.Payable
   167  }