github.com/klaytn/klaytn@v1.12.1/api/tx_args.go (about)

     1  // Modifications Copyright 2019 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from internal/ethapi/api.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package api
    22  
    23  import (
    24  	"bytes"
    25  	"context"
    26  	"errors"
    27  	"fmt"
    28  	"math/big"
    29  	"reflect"
    30  
    31  	"github.com/klaytn/klaytn/blockchain/types"
    32  	"github.com/klaytn/klaytn/blockchain/types/accountkey"
    33  	"github.com/klaytn/klaytn/common"
    34  	"github.com/klaytn/klaytn/common/hexutil"
    35  	"github.com/klaytn/klaytn/common/math"
    36  	"github.com/klaytn/klaytn/networks/rpc"
    37  	"github.com/klaytn/klaytn/params"
    38  	"github.com/klaytn/klaytn/rlp"
    39  )
    40  
    41  var (
    42  	errTxArgInvalidInputData = errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`)
    43  	errTxArgInvalidFeePayer  = errors.New("invalid fee payer is set")
    44  	errTxArgNilTxType        = errors.New("tx should have a type value")
    45  	errTxArgNilContractData  = errors.New(`contract creation without any data provided`)
    46  	errTxArgNilSenderSig     = errors.New("sender signature is not set")
    47  	errTxArgNilNonce         = errors.New("nonce of the sender is not set")
    48  	errTxArgNilGas           = errors.New("gas limit is not set")
    49  	errTxArgNilGasPrice      = errors.New("gas price is not set")
    50  	errNotForFeeDelegationTx = errors.New("fee-delegation type transactions are not allowed to use this API")
    51  )
    52  
    53  // isTxField checks whether the string is a field name of the specific txType.
    54  // isTxField[txType][txFieldName] has true/false.
    55  var isTxField = func() map[types.TxType]map[string]bool {
    56  	mapOfFieldMap := map[types.TxType]map[string]bool{}
    57  	internalDataTypes := map[types.TxType]interface{}{
    58  		// since legacy tx has optional fields, some fields can be omitted
    59  		// types.TxTypeLegacyTransaction:                           types.TxInternalDataLegacy{},
    60  		types.TxTypeValueTransfer:                               types.TxInternalDataValueTransfer{},
    61  		types.TxTypeFeeDelegatedValueTransfer:                   types.TxInternalDataFeeDelegatedValueTransfer{},
    62  		types.TxTypeFeeDelegatedValueTransferWithRatio:          types.TxInternalDataFeeDelegatedValueTransferWithRatio{},
    63  		types.TxTypeValueTransferMemo:                           types.TxInternalDataValueTransferMemo{},
    64  		types.TxTypeFeeDelegatedValueTransferMemo:               types.TxInternalDataFeeDelegatedValueTransferMemo{},
    65  		types.TxTypeFeeDelegatedValueTransferMemoWithRatio:      types.TxInternalDataFeeDelegatedValueTransferMemoWithRatio{},
    66  		types.TxTypeAccountUpdate:                               types.TxInternalDataAccountUpdate{},
    67  		types.TxTypeFeeDelegatedAccountUpdate:                   types.TxInternalDataFeeDelegatedAccountUpdate{},
    68  		types.TxTypeFeeDelegatedAccountUpdateWithRatio:          types.TxInternalDataFeeDelegatedAccountUpdateWithRatio{},
    69  		types.TxTypeSmartContractDeploy:                         types.TxInternalDataSmartContractDeploy{},
    70  		types.TxTypeFeeDelegatedSmartContractDeploy:             types.TxInternalDataFeeDelegatedSmartContractDeploy{},
    71  		types.TxTypeFeeDelegatedSmartContractDeployWithRatio:    types.TxInternalDataFeeDelegatedSmartContractDeployWithRatio{},
    72  		types.TxTypeSmartContractExecution:                      types.TxInternalDataSmartContractExecution{},
    73  		types.TxTypeFeeDelegatedSmartContractExecution:          types.TxInternalDataFeeDelegatedSmartContractExecution{},
    74  		types.TxTypeFeeDelegatedSmartContractExecutionWithRatio: types.TxInternalDataFeeDelegatedSmartContractExecutionWithRatio{},
    75  		types.TxTypeCancel:                                      types.TxInternalDataCancel{},
    76  		types.TxTypeFeeDelegatedCancel:                          types.TxInternalDataFeeDelegatedCancel{},
    77  		types.TxTypeFeeDelegatedCancelWithRatio:                 types.TxInternalDataFeeDelegatedCancelWithRatio{},
    78  		types.TxTypeChainDataAnchoring:                          types.TxInternalDataChainDataAnchoring{},
    79  		types.TxTypeFeeDelegatedChainDataAnchoring:              types.TxInternalDataFeeDelegatedChainDataAnchoring{},
    80  		types.TxTypeFeeDelegatedChainDataAnchoringWithRatio:     types.TxInternalDataFeeDelegatedChainDataAnchoringWithRatio{},
    81  	}
    82  
    83  	// generate field maps for each tx type
    84  	for txType, internalData := range internalDataTypes {
    85  		fieldMap := map[string]bool{}
    86  		internalDataType := reflect.TypeOf(internalData)
    87  
    88  		// key of filedMap is tx field name and value of fieldMap means the existence of field name
    89  		for i := 0; i < internalDataType.NumField(); i++ {
    90  			fieldMap[internalDataType.Field(i).Name] = true
    91  		}
    92  
    93  		// additional field of SendTxArgs to support various tx types
    94  		fieldMap["TypeInt"] = true
    95  		// additional field of SendTxArgs to support a legacy tx field (skip checking)
    96  		fieldMap["Data"] = false
    97  
    98  		mapOfFieldMap[txType] = fieldMap
    99  	}
   100  	return mapOfFieldMap
   101  }()
   102  
   103  type NewTxArgs interface {
   104  	setDefaults(context.Context, Backend) error
   105  	toTransaction() (*types.Transaction, error)
   106  	from() common.Address
   107  	gas() *hexutil.Uint64
   108  	gasPrice() *hexutil.Big
   109  	nonce() *hexutil.Uint64
   110  	setGas(*hexutil.Uint64)
   111  	setGasPrice(*hexutil.Big)
   112  }
   113  
   114  // SendTxArgs represents the arguments to submit a new transaction into the transaction pool.
   115  type SendTxArgs struct {
   116  	TypeInt              *types.TxType   `json:"typeInt"`
   117  	From                 common.Address  `json:"from"`
   118  	Recipient            *common.Address `json:"to"`
   119  	GasLimit             *hexutil.Uint64 `json:"gas"`
   120  	Price                *hexutil.Big    `json:"gasPrice"`
   121  	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
   122  	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
   123  	Amount               *hexutil.Big    `json:"value"`
   124  	AccountNonce         *hexutil.Uint64 `json:"nonce"`
   125  	// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
   126  	// newer name and should be preferred by clients.
   127  	Data    *hexutil.Bytes `json:"data"`
   128  	Payload *hexutil.Bytes `json:"input"`
   129  
   130  	CodeFormat    *params.CodeFormat `json:"codeFormat"`
   131  	HumanReadable *bool              `json:"humanReadable"`
   132  
   133  	Key *hexutil.Bytes `json:"key"`
   134  
   135  	AccessList *types.AccessList `json:"accessList,omitempty"`
   136  	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
   137  
   138  	FeePayer *common.Address `json:"feePayer"`
   139  	FeeRatio *types.FeeRatio `json:"feeRatio"`
   140  
   141  	TxSignatures types.TxSignaturesJSON `json:"signatures"`
   142  }
   143  
   144  // setDefaults is a helper function that fills in default values for unspecified common tx fields.
   145  func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
   146  	isMagma := b.ChainConfig().IsMagmaForkEnabled(new(big.Int).Add(b.CurrentBlock().Number(), big.NewInt(1)))
   147  
   148  	if args.TypeInt == nil {
   149  		args.TypeInt = new(types.TxType)
   150  		*args.TypeInt = types.TxTypeLegacyTransaction
   151  	}
   152  	if args.GasLimit == nil {
   153  		args.GasLimit = new(hexutil.Uint64)
   154  		*args.GasLimit = hexutil.Uint64(90000)
   155  	}
   156  	// Eth typed transactions requires chainId.
   157  	if args.TypeInt.IsEthTypedTransaction() {
   158  		if args.ChainID == nil {
   159  			args.ChainID = (*hexutil.Big)(b.ChainConfig().ChainID)
   160  		}
   161  	}
   162  	// For the transaction that do not use the gasPrice field, the default value of gasPrice is not set.
   163  	if args.Price == nil && *args.TypeInt != types.TxTypeEthereumDynamicFee {
   164  		// b.SuggestPrice = unitPrice, for before Magma
   165  		//                = baseFee * 2,   for after Magma
   166  		price, err := b.SuggestPrice(ctx)
   167  		if err != nil {
   168  			return err
   169  		}
   170  		args.Price = (*hexutil.Big)(price)
   171  	}
   172  
   173  	if *args.TypeInt == types.TxTypeEthereumDynamicFee {
   174  		gasPrice, err := b.SuggestPrice(ctx)
   175  		if err != nil {
   176  			return err
   177  		}
   178  		if args.MaxPriorityFeePerGas == nil {
   179  			args.MaxPriorityFeePerGas = (*hexutil.Big)(gasPrice)
   180  		}
   181  		if args.MaxFeePerGas == nil {
   182  			// Before Magma hard fork, `gasFeeCap` was set to `baseFee*2 + maxPriorityFeePerGas` by default.
   183  			gasFeeCap := new(big.Int).Add(
   184  				(*big.Int)(args.MaxPriorityFeePerGas),
   185  				new(big.Int).Mul(new(big.Int).SetUint64(params.ZeroBaseFee), big.NewInt(2)),
   186  			)
   187  			if isMagma {
   188  				// After Magma hard fork, `gasFeeCap` was set to `baseFee*2` by default.
   189  				gasFeeCap = gasPrice
   190  			}
   191  			args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap)
   192  		}
   193  		if isMagma {
   194  			if args.MaxFeePerGas.ToInt().Cmp(new(big.Int).Div(gasPrice, common.Big2)) < 0 {
   195  				return fmt.Errorf("maxFeePerGas (%v) < BaseFee (%v)", args.MaxFeePerGas, gasPrice)
   196  			}
   197  		} else if args.MaxPriorityFeePerGas.ToInt().Cmp(gasPrice) != 0 || args.MaxFeePerGas.ToInt().Cmp(gasPrice) != 0 {
   198  			return fmt.Errorf("only %s is allowed to be used as maxFeePerGas and maxPriorityPerGas", gasPrice.Text(16))
   199  		}
   200  		if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   201  			return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   202  		}
   203  	}
   204  	if args.AccountNonce == nil {
   205  		nonce := b.GetPoolNonce(ctx, args.From)
   206  		args.AccountNonce = (*hexutil.Uint64)(&nonce)
   207  	}
   208  
   209  	return nil
   210  }
   211  
   212  // checkArgs checks the validity of SendTxArgs values.
   213  // The each tx types has its own validation logic to give detailed errors to users.
   214  func (args *SendTxArgs) checkArgs() error {
   215  	if args.TypeInt == nil {
   216  		return errTxArgNilTxType
   217  	}
   218  	// Skip ethereum transaction type since it has optional fields
   219  	if args.TypeInt.IsEthereumTransaction() {
   220  		return nil
   221  	}
   222  
   223  	argsType := reflect.TypeOf(*args)
   224  	argsValue := reflect.ValueOf(*args)
   225  
   226  	for i := 0; i < argsType.NumField(); i++ {
   227  		// Skip From since it is an essential field and a non-pointer value
   228  		// Skip TxSignatures since the value is not considered by all APIs
   229  		if argsType.Field(i).Name == "From" || argsType.Field(i).Name == "TxSignatures" {
   230  			continue
   231  		}
   232  
   233  		// An args field doesn't have a value but the field name exist on the tx type
   234  		if argsValue.Field(i).IsNil() && isTxField[*args.TypeInt][argsType.Field(i).Name] {
   235  			// Allow only contract deploying txs to set the recipient as nil
   236  			if (*args.TypeInt).IsContractDeploy() && argsType.Field(i).Name == "Recipient" {
   237  				continue
   238  			}
   239  			return errors.New((string)(argsType.Field(i).Tag) + " is required for " + (*args.TypeInt).String())
   240  		}
   241  
   242  		// An args field has a value but the field name doesn't exist on the tx type
   243  		if !argsValue.Field(i).IsNil() && !isTxField[*args.TypeInt][argsType.Field(i).Name] {
   244  			return errors.New((string)(argsType.Field(i).Tag) + " is not a field of " + (*args.TypeInt).String())
   245  		}
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  // genTxValuesMap generates a value map used used in "NewTransactionWithMap" function.
   252  // This function assigned all non-nil values regardless of the tx type.
   253  // Invalid values in the map will be validated in "NewTransactionWithMap" function.
   254  func (args *SendTxArgs) genTxValuesMap() map[types.TxValueKeyType]interface{} {
   255  	values := make(map[types.TxValueKeyType]interface{})
   256  
   257  	// common tx fields. They should have values after executing "setDefaults" function.
   258  	if args.TypeInt == nil || args.AccountNonce == nil || args.GasLimit == nil {
   259  		return values
   260  	}
   261  	// GasPrice can be an optional tx filed for TxTypeEthereumDynamicFee
   262  	if args.Price == nil && *args.TypeInt != types.TxTypeEthereumDynamicFee {
   263  		return values
   264  	}
   265  
   266  	if !args.TypeInt.IsEthereumTransaction() {
   267  		values[types.TxValueKeyFrom] = args.From
   268  	}
   269  	values[types.TxValueKeyNonce] = uint64(*args.AccountNonce)
   270  	values[types.TxValueKeyGasLimit] = uint64(*args.GasLimit)
   271  
   272  	// optional tx fields
   273  	if args.Price != nil {
   274  		values[types.TxValueKeyGasPrice] = (*big.Int)(args.Price)
   275  	}
   276  	if args.TypeInt.IsContractDeploy() || args.TypeInt.IsEthereumTransaction() {
   277  		// contract deploy type and ethereum tx types allow nil as TxValueKeyTo value
   278  		values[types.TxValueKeyTo] = (*common.Address)(args.Recipient)
   279  	} else if args.Recipient != nil {
   280  		values[types.TxValueKeyTo] = *args.Recipient
   281  	}
   282  	if args.FeePayer != nil {
   283  		values[types.TxValueKeyFeePayer] = *args.FeePayer
   284  	}
   285  	if args.FeeRatio != nil {
   286  		values[types.TxValueKeyFeeRatioOfFeePayer] = *args.FeeRatio
   287  	}
   288  	if args.Amount != nil {
   289  		values[types.TxValueKeyAmount] = (*big.Int)(args.Amount)
   290  	} else if args.TypeInt.IsEthereumTransaction() {
   291  		values[types.TxValueKeyAmount] = common.Big0
   292  	}
   293  	if args.Payload != nil {
   294  		// chain data anchoring type uses the TxValueKeyAnchoredData field
   295  		if args.TypeInt.IsChainDataAnchoring() {
   296  			values[types.TxValueKeyAnchoredData] = ([]byte)(*args.Payload)
   297  		} else {
   298  			values[types.TxValueKeyData] = ([]byte)(*args.Payload)
   299  		}
   300  	} else if args.TypeInt.IsEthereumTransaction() {
   301  		// For Ethereum transactions, Payload is an optional field.
   302  		values[types.TxValueKeyData] = []byte{}
   303  	}
   304  	if args.CodeFormat != nil {
   305  		values[types.TxValueKeyCodeFormat] = *args.CodeFormat
   306  	}
   307  	if args.HumanReadable != nil {
   308  		values[types.TxValueKeyHumanReadable] = *args.HumanReadable
   309  	}
   310  	if args.Key != nil {
   311  		serializer := accountkey.NewAccountKeySerializer()
   312  		if err := rlp.DecodeBytes(*args.Key, &serializer); err == nil {
   313  			values[types.TxValueKeyAccountKey] = serializer.GetKey()
   314  		}
   315  	}
   316  	if args.ChainID != nil {
   317  		values[types.TxValueKeyChainID] = (*big.Int)(args.ChainID)
   318  	}
   319  	if args.AccessList != nil {
   320  		values[types.TxValueKeyAccessList] = *args.AccessList
   321  	}
   322  	if args.MaxPriorityFeePerGas != nil {
   323  		values[types.TxValueKeyGasTipCap] = (*big.Int)(args.MaxPriorityFeePerGas)
   324  	}
   325  	if args.MaxFeePerGas != nil {
   326  		values[types.TxValueKeyGasFeeCap] = (*big.Int)(args.MaxFeePerGas)
   327  	}
   328  
   329  	return values
   330  }
   331  
   332  // toTransaction returns an unsigned transaction filled with values in SendTxArgs.
   333  func (args *SendTxArgs) toTransaction() (*types.Transaction, error) {
   334  	var input []byte
   335  
   336  	// provide detailed error messages to users (optional)
   337  	if err := args.checkArgs(); err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	// for TxTypeLegacyTransaction
   342  	if *args.TypeInt == types.TxTypeLegacyTransaction {
   343  		if args.Data != nil && args.Payload != nil && !bytes.Equal(*args.Data, *args.Payload) {
   344  			return nil, errTxArgInvalidInputData
   345  		}
   346  
   347  		if args.Data != nil {
   348  			input = *args.Data
   349  		} else if args.Payload != nil {
   350  			input = *args.Payload
   351  		}
   352  
   353  		if args.Recipient == nil {
   354  			if len(input) == 0 {
   355  				return nil, errTxArgNilContractData
   356  			}
   357  			return types.NewContractCreation(uint64(*args.AccountNonce), (*big.Int)(args.Amount), uint64(*args.GasLimit), (*big.Int)(args.Price), input), nil
   358  		}
   359  		return types.NewTransaction(uint64(*args.AccountNonce), *args.Recipient, (*big.Int)(args.Amount), uint64(*args.GasLimit), (*big.Int)(args.Price), input), nil
   360  	}
   361  
   362  	// for other tx types except TxTypeLegacyTransaction
   363  	values := args.genTxValuesMap()
   364  	return types.NewTransactionWithMap(*args.TypeInt, values)
   365  }
   366  
   367  func (args *SendTxArgs) from() common.Address {
   368  	return args.From
   369  }
   370  
   371  func (args *SendTxArgs) gas() *hexutil.Uint64 {
   372  	return args.GasLimit
   373  }
   374  
   375  func (args *SendTxArgs) gasPrice() *hexutil.Big {
   376  	return args.Price
   377  }
   378  
   379  func (args *SendTxArgs) nonce() *hexutil.Uint64 {
   380  	return args.AccountNonce
   381  }
   382  
   383  func (args *SendTxArgs) setGas(gas *hexutil.Uint64) {
   384  	args.GasLimit = gas
   385  }
   386  
   387  func (args *SendTxArgs) setGasPrice(gasPrice *hexutil.Big) {
   388  	args.Price = gasPrice
   389  }
   390  
   391  type ValueTransferTxArgs struct {
   392  	From     common.Address  `json:"from"`
   393  	Gas      *hexutil.Uint64 `json:"gas"`
   394  	GasPrice *hexutil.Big    `json:"gasPrice"`
   395  	Nonce    *hexutil.Uint64 `json:"nonce"`
   396  	To       common.Address  `json:"to"`
   397  	Value    *hexutil.Big    `json:"value"`
   398  }
   399  
   400  func (args *ValueTransferTxArgs) from() common.Address {
   401  	return args.From
   402  }
   403  
   404  func (args *ValueTransferTxArgs) gas() *hexutil.Uint64 {
   405  	return args.Gas
   406  }
   407  
   408  func (args *ValueTransferTxArgs) gasPrice() *hexutil.Big {
   409  	return args.GasPrice
   410  }
   411  
   412  func (args *ValueTransferTxArgs) nonce() *hexutil.Uint64 {
   413  	return args.Nonce
   414  }
   415  
   416  func (args *ValueTransferTxArgs) setGas(gas *hexutil.Uint64) {
   417  	args.Gas = gas
   418  }
   419  
   420  func (args *ValueTransferTxArgs) setGasPrice(gasPrice *hexutil.Big) {
   421  	args.GasPrice = gasPrice
   422  }
   423  
   424  // setDefaults is a helper function that fills in default values for unspecified tx fields.
   425  func (args *ValueTransferTxArgs) setDefaults(ctx context.Context, b Backend) error {
   426  	if args.Gas == nil {
   427  		args.Gas = new(hexutil.Uint64)
   428  		*(*uint64)(args.Gas) = 90000
   429  	}
   430  	if args.GasPrice == nil {
   431  		price, err := b.SuggestPrice(ctx)
   432  		if err != nil {
   433  			return err
   434  		}
   435  		args.GasPrice = (*hexutil.Big)(price)
   436  	}
   437  	if args.Nonce == nil {
   438  		nonce := b.GetPoolNonce(ctx, args.From)
   439  		args.Nonce = (*hexutil.Uint64)(&nonce)
   440  	}
   441  	return nil
   442  }
   443  
   444  func (args *ValueTransferTxArgs) toTransaction() (*types.Transaction, error) {
   445  	tx, err := types.NewTransactionWithMap(types.TxTypeValueTransfer, map[types.TxValueKeyType]interface{}{
   446  		types.TxValueKeyNonce:    (uint64)(*args.Nonce),
   447  		types.TxValueKeyGasLimit: (uint64)(*args.Gas),
   448  		types.TxValueKeyGasPrice: (*big.Int)(args.GasPrice),
   449  		types.TxValueKeyFrom:     args.From,
   450  		types.TxValueKeyTo:       args.To,
   451  		types.TxValueKeyAmount:   (*big.Int)(args.Value),
   452  	})
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	return tx, nil
   458  }
   459  
   460  type AccountUpdateTxArgs struct {
   461  	From     common.Address  `json:"from"`
   462  	Gas      *hexutil.Uint64 `json:"gas"`
   463  	GasPrice *hexutil.Big    `json:"gasPrice"`
   464  	Nonce    *hexutil.Uint64 `json:"nonce"`
   465  	Key      *hexutil.Bytes  `json:"key"`
   466  }
   467  
   468  func (args *AccountUpdateTxArgs) from() common.Address {
   469  	return args.From
   470  }
   471  
   472  func (args *AccountUpdateTxArgs) gas() *hexutil.Uint64 {
   473  	return args.Gas
   474  }
   475  
   476  func (args *AccountUpdateTxArgs) gasPrice() *hexutil.Big {
   477  	return args.GasPrice
   478  }
   479  
   480  func (args *AccountUpdateTxArgs) nonce() *hexutil.Uint64 {
   481  	return args.Nonce
   482  }
   483  
   484  func (args *AccountUpdateTxArgs) setGas(gas *hexutil.Uint64) {
   485  	args.Gas = gas
   486  }
   487  
   488  func (args *AccountUpdateTxArgs) setGasPrice(gasPrice *hexutil.Big) {
   489  	args.GasPrice = gasPrice
   490  }
   491  
   492  // setDefaults is a helper function that fills in default values for unspecified tx fields.
   493  func (args *AccountUpdateTxArgs) setDefaults(ctx context.Context, b Backend) error {
   494  	if args.Gas == nil {
   495  		args.Gas = new(hexutil.Uint64)
   496  		*(*uint64)(args.Gas) = 90000
   497  	}
   498  	if args.GasPrice == nil {
   499  		price, err := b.SuggestPrice(ctx)
   500  		if err != nil {
   501  			return err
   502  		}
   503  		args.GasPrice = (*hexutil.Big)(price)
   504  	}
   505  	if args.Nonce == nil {
   506  		nonce := b.GetPoolNonce(ctx, args.From)
   507  		args.Nonce = (*hexutil.Uint64)(&nonce)
   508  	}
   509  	return nil
   510  }
   511  
   512  func (args *AccountUpdateTxArgs) toTransaction() (*types.Transaction, error) {
   513  	serializer := accountkey.NewAccountKeySerializer()
   514  
   515  	if err := rlp.DecodeBytes(*args.Key, &serializer); err != nil {
   516  		return nil, err
   517  	}
   518  	tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, map[types.TxValueKeyType]interface{}{
   519  		types.TxValueKeyNonce:      (uint64)(*args.Nonce),
   520  		types.TxValueKeyGasLimit:   (uint64)(*args.Gas),
   521  		types.TxValueKeyGasPrice:   (*big.Int)(args.GasPrice),
   522  		types.TxValueKeyFrom:       args.From,
   523  		types.TxValueKeyAccountKey: serializer.GetKey(),
   524  	})
   525  	if err != nil {
   526  		return nil, err
   527  	}
   528  
   529  	return tx, nil
   530  }
   531  
   532  // EthTransactionArgs represents the arguments to construct a new transaction
   533  // or a message call.
   534  // TransactionArgs in go-ethereum has been renamed to EthTransactionArgs.
   535  // TransactionArgs is defined in go-ethereum's internal package, so TransactionArgs is redefined here as EthTransactionArgs.
   536  type EthTransactionArgs struct {
   537  	From                 *common.Address `json:"from"`
   538  	To                   *common.Address `json:"to"`
   539  	Gas                  *hexutil.Uint64 `json:"gas"`
   540  	GasPrice             *hexutil.Big    `json:"gasPrice"`
   541  	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
   542  	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
   543  	Value                *hexutil.Big    `json:"value"`
   544  	Nonce                *hexutil.Uint64 `json:"nonce"`
   545  
   546  	// We accept "data" and "input" for backwards-compatibility reasons.
   547  	// "input" is the newer name and should be preferred by clients.
   548  	// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
   549  	Data  *hexutil.Bytes `json:"data"`
   550  	Input *hexutil.Bytes `json:"input"`
   551  
   552  	// Introduced by AccessListTxType transaction.
   553  	AccessList *types.AccessList `json:"accessList,omitempty"`
   554  	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
   555  }
   556  
   557  // from retrieves the transaction sender address.
   558  func (args *EthTransactionArgs) from() common.Address {
   559  	if args.From == nil {
   560  		return common.Address{}
   561  	}
   562  	return *args.From
   563  }
   564  
   565  func (args *EthTransactionArgs) gas() *hexutil.Uint64 {
   566  	return args.Gas
   567  }
   568  
   569  func (args *EthTransactionArgs) gasPrice() *hexutil.Big {
   570  	return args.GasPrice
   571  }
   572  
   573  func (args *EthTransactionArgs) nonce() *hexutil.Uint64 {
   574  	return args.Nonce
   575  }
   576  
   577  // data retrieves the transaction calldata. Input field is preferred.
   578  func (args *EthTransactionArgs) data() []byte {
   579  	if args.Input != nil {
   580  		return *args.Input
   581  	}
   582  	if args.Data != nil {
   583  		return *args.Data
   584  	}
   585  	return nil
   586  }
   587  
   588  func (args *EthTransactionArgs) setGas(gas *hexutil.Uint64) {
   589  	args.Gas = gas
   590  }
   591  
   592  func (args *EthTransactionArgs) setGasPrice(gasPrice *hexutil.Big) {
   593  	args.GasPrice = gasPrice
   594  }
   595  
   596  // setDefaults fills in default values for unspecified tx fields.
   597  func (args *EthTransactionArgs) setDefaults(ctx context.Context, b Backend) error {
   598  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   599  		return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   600  	}
   601  	// After london, default to 1559 uncles gasPrice is set
   602  	head := b.CurrentBlock().Header()
   603  	isMagma := head.BaseFee != nil
   604  
   605  	fixedBaseFee := new(big.Int).SetUint64(params.ZeroBaseFee)
   606  
   607  	// b.SuggestPrice = unitPrice, for before Magma
   608  	//                = baseFee,   for after Magma
   609  	gasPrice, err := b.SuggestPrice(ctx)
   610  	if err != nil {
   611  		return err
   612  	}
   613  
   614  	// If user specifies both maxPriorityFee and maxFee, then we do not
   615  	// need to consult the chain for defaults. It's definitely a London tx.
   616  	if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil {
   617  		if b.ChainConfig().IsEthTxTypeForkEnabled(head.Number) && args.GasPrice == nil {
   618  			if args.MaxPriorityFeePerGas == nil {
   619  				args.MaxPriorityFeePerGas = (*hexutil.Big)(gasPrice)
   620  			}
   621  			if args.MaxFeePerGas == nil {
   622  				// Before Magma hard fork, `gasFeeCap` was set to `baseFee*2 + maxPriorityFeePerGas` by default.
   623  				gasFeeCap := new(big.Int).Add(
   624  					(*big.Int)(args.MaxPriorityFeePerGas),
   625  					new(big.Int).Mul(fixedBaseFee, big.NewInt(2)),
   626  				)
   627  				if isMagma {
   628  					// After Magma hard fork, `gasFeeCap` was set to `baseFee*2` by default.
   629  					gasFeeCap = gasPrice
   630  				}
   631  				args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap)
   632  			}
   633  			if isMagma {
   634  				if args.MaxFeePerGas.ToInt().Cmp(new(big.Int).Div(gasPrice, common.Big2)) < 0 {
   635  					return fmt.Errorf("maxFeePerGas (%v) < BaseFee (%v)", args.MaxFeePerGas, gasPrice)
   636  				}
   637  			} else if args.MaxPriorityFeePerGas.ToInt().Cmp(gasPrice) != 0 || args.MaxFeePerGas.ToInt().Cmp(gasPrice) != 0 {
   638  				return fmt.Errorf("only %s is allowed to be used as maxFeePerGas and maxPriorityPerGas", gasPrice.Text(16))
   639  			}
   640  			if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   641  				return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   642  			}
   643  		} else {
   644  			if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
   645  				return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
   646  			}
   647  			if args.GasPrice == nil {
   648  				// TODO-Klaytn: Original logic of Ethereum uses b.SuggestTipCap which suggests TipCap, not a GasPrice.
   649  				// But Klaytn currently uses fixed unit price determined by Governance, so using b.SuggestPrice
   650  				// is fine as now.
   651  				if b.ChainConfig().IsEthTxTypeForkEnabled(head.Number) {
   652  					// TODO-Klaytn: Klaytn is using fixed BaseFee(0) as now but
   653  					// if we apply dynamic BaseFee, we should add calculated BaseFee instead of params.ZeroBaseFee.
   654  					gasPrice.Add(gasPrice, new(big.Int).SetUint64(params.ZeroBaseFee))
   655  				}
   656  				args.GasPrice = (*hexutil.Big)(gasPrice)
   657  			}
   658  		}
   659  	} else {
   660  		// Both maxPriorityFee and maxFee set by caller. Sanity-check their internal relation
   661  		if isMagma {
   662  			if args.MaxFeePerGas.ToInt().Cmp(new(big.Int).Div(gasPrice, common.Big2)) < 0 {
   663  				return fmt.Errorf("maxFeePerGas (%v) < BaseFee (%v)", args.MaxFeePerGas, gasPrice)
   664  			}
   665  		} else {
   666  			if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   667  				return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   668  			}
   669  		}
   670  	}
   671  	if args.Value == nil {
   672  		args.Value = new(hexutil.Big)
   673  	}
   674  	if args.Nonce == nil {
   675  		nonce := b.GetPoolNonce(ctx, args.from())
   676  		args.Nonce = (*hexutil.Uint64)(&nonce)
   677  	}
   678  	if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
   679  		return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
   680  	}
   681  	if args.To == nil && len(args.data()) == 0 {
   682  		return errors.New(`contract creation without any data provided`)
   683  	}
   684  	// Estimate the gas usage if necessary.
   685  	if args.Gas == nil {
   686  		// These fields are immutable during the estimation, safe to
   687  		// pass the pointer directly.
   688  		data := args.data()
   689  		callArgs := EthTransactionArgs{
   690  			From:                 args.From,
   691  			To:                   args.To,
   692  			GasPrice:             args.GasPrice,
   693  			MaxFeePerGas:         args.MaxFeePerGas,
   694  			MaxPriorityFeePerGas: args.MaxPriorityFeePerGas,
   695  			Value:                args.Value,
   696  			Data:                 (*hexutil.Bytes)(&data),
   697  			AccessList:           args.AccessList,
   698  		}
   699  		pendingBlockNr := rpc.NewBlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
   700  		gasCap := uint64(0)
   701  		if rpcGasCap := b.RPCGasCap(); rpcGasCap != nil {
   702  			gasCap = rpcGasCap.Uint64()
   703  		}
   704  		estimated, err := EthDoEstimateGas(ctx, b, callArgs, pendingBlockNr, gasCap)
   705  		if err != nil {
   706  			return err
   707  		}
   708  		args.Gas = &estimated
   709  		logger.Trace("Estimate gas usage automatically", "gas", args.Gas)
   710  	}
   711  	if args.ChainID == nil {
   712  		id := (*hexutil.Big)(b.ChainConfig().ChainID)
   713  		args.ChainID = id
   714  	}
   715  	return nil
   716  }
   717  
   718  // ToMessage change EthTransactionArgs to types.Transaction in Klaytn.
   719  func (args *EthTransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64) (*types.Transaction, error) {
   720  	// Reject invalid combinations of pre- and post-1559 fee styles
   721  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   722  		return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   723  	} else if args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil {
   724  		if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   725  			return nil, errors.New("MaxPriorityFeePerGas is greater than MaxFeePerGas")
   726  		}
   727  	}
   728  	// Set sender address or use zero address if none specified.
   729  	addr := args.from()
   730  
   731  	// Set default gas & gas price if none were set
   732  	gas := globalGasCap
   733  	if gas == 0 {
   734  		gas = uint64(math.MaxUint64 / 2)
   735  	}
   736  	if args.Gas != nil {
   737  		gas = uint64(*args.Gas)
   738  	}
   739  	if globalGasCap != 0 && globalGasCap < gas {
   740  		logger.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
   741  		gas = globalGasCap
   742  	}
   743  
   744  	// Do not update gasPrice unless any of args.GasPrice and args.MaxFeePerGas is specified.
   745  	gasPrice := new(big.Int)
   746  	if baseFee.Cmp(new(big.Int).SetUint64(params.ZeroBaseFee)) == 0 {
   747  		// If there's no basefee, then it must be a non-1559 execution
   748  		if args.GasPrice != nil {
   749  			gasPrice = args.GasPrice.ToInt()
   750  		} else if args.MaxFeePerGas != nil {
   751  			gasPrice = args.MaxFeePerGas.ToInt()
   752  		}
   753  	} else {
   754  		if args.GasPrice != nil {
   755  			gasPrice = args.GasPrice.ToInt()
   756  		} else if args.MaxFeePerGas != nil {
   757  			// User specified 1559 gas fields (or none), use those
   758  			gasPrice = args.MaxFeePerGas.ToInt()
   759  		} else {
   760  			// User specified neither GasPrice nor MaxFeePerGas, use baseFee
   761  			gasPrice = new(big.Int).Mul(baseFee, common.Big2)
   762  		}
   763  	}
   764  
   765  	value := new(big.Int)
   766  	if args.Value != nil {
   767  		value = args.Value.ToInt()
   768  	}
   769  	data := args.data()
   770  
   771  	var accessList types.AccessList
   772  	if args.AccessList != nil {
   773  		accessList = *args.AccessList
   774  	}
   775  	return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false, intrinsicGas, accessList), nil
   776  }
   777  
   778  // toTransaction converts the arguments to a transaction.
   779  // This assumes that setDefaults has been called.
   780  func (args *EthTransactionArgs) toTransaction() (*types.Transaction, error) {
   781  	var tx *types.Transaction
   782  	switch {
   783  	case args.MaxFeePerGas != nil:
   784  		al := types.AccessList{}
   785  		if args.AccessList != nil {
   786  			al = *args.AccessList
   787  		}
   788  		tx = types.NewTx(&types.TxInternalDataEthereumDynamicFee{
   789  			ChainID:      (*big.Int)(args.ChainID),
   790  			AccountNonce: uint64(*args.Nonce),
   791  			GasTipCap:    (*big.Int)(args.MaxPriorityFeePerGas),
   792  			GasFeeCap:    (*big.Int)(args.MaxFeePerGas),
   793  			GasLimit:     uint64(*args.Gas),
   794  			Recipient:    args.To,
   795  			Amount:       (*big.Int)(args.Value),
   796  			Payload:      args.data(),
   797  			AccessList:   al,
   798  		})
   799  	case args.AccessList != nil:
   800  		tx = types.NewTx(&types.TxInternalDataEthereumAccessList{
   801  			ChainID:      (*big.Int)(args.ChainID),
   802  			AccountNonce: uint64(*args.Nonce),
   803  			Recipient:    args.To,
   804  			GasLimit:     uint64(*args.Gas),
   805  			Price:        (*big.Int)(args.GasPrice),
   806  			Amount:       (*big.Int)(args.Value),
   807  			Payload:      args.data(),
   808  			AccessList:   *args.AccessList,
   809  		})
   810  	default:
   811  		tx = types.NewTx(&types.TxInternalDataLegacy{
   812  			AccountNonce: uint64(*args.Nonce),
   813  			Price:        (*big.Int)(args.GasPrice),
   814  			GasLimit:     uint64(*args.Gas),
   815  			Recipient:    args.To,
   816  			Amount:       (*big.Int)(args.Value),
   817  			Payload:      args.data(),
   818  		})
   819  	}
   820  	return tx, nil
   821  }