2021-09-03 15:55:37 +00:00
package keeper
import (
2022-08-05 13:00:31 +00:00
"math"
2021-10-04 14:58:06 +00:00
"math/big"
2022-07-28 13:43:49 +00:00
sdkmath "cosmossdk.io/math"
2021-09-03 15:55:37 +00:00
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
2022-06-19 09:43:41 +00:00
evmtypes "github.com/evmos/ethermint/x/evm/types"
2021-09-03 15:55:37 +00:00
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
2022-08-05 13:00:31 +00:00
// DefaultPriorityReduction is the default amount of price values required for 1 unit of priority.
// Because priority is `int64` while price is `big.Int`, it's necessary to scale down the range to keep it more pratical.
// The default value is the same as the `sdk.DefaultPowerReduction`.
var DefaultPriorityReduction = sdk . DefaultPowerReduction
2021-09-03 15:55:37 +00:00
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
2022-08-05 13:00:31 +00:00
// returns (effectiveFee, priority, error)
2021-09-22 10:26:29 +00:00
func ( k Keeper ) DeductTxCostsFromUserBalance (
2021-09-03 15:55:37 +00:00
ctx sdk . Context ,
msgEthTx evmtypes . MsgEthereumTx ,
txData evmtypes . TxData ,
denom string ,
2021-10-04 14:58:06 +00:00
homestead , istanbul , london bool ,
2022-08-05 13:00:31 +00:00
) ( fees sdk . Coins , priority int64 , err error ) {
2021-09-03 15:55:37 +00:00
isContractCreation := txData . GetTo ( ) == nil
// fetch sender account from signature
2021-09-22 10:26:29 +00:00
signerAcc , err := authante . GetSignerAcc ( ctx , k . accountKeeper , msgEthTx . GetFrom ( ) )
2021-09-03 15:55:37 +00:00
if err != nil {
2022-08-05 13:00:31 +00:00
return nil , 0 , sdkerrors . Wrapf ( err , "account not found for sender %s" , msgEthTx . From )
2021-09-03 15:55:37 +00:00
}
gasLimit := txData . GetGas ( )
var accessList ethtypes . AccessList
if txData . GetAccessList ( ) != nil {
accessList = txData . GetAccessList ( )
}
intrinsicGas , err := core . IntrinsicGas ( txData . GetData ( ) , accessList , isContractCreation , homestead , istanbul )
if err != nil {
2022-08-05 13:00:31 +00:00
return nil , 0 , sdkerrors . Wrapf (
2021-09-03 15:55:37 +00:00
err ,
2021-11-26 14:19:28 +00:00
"failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t" ,
2021-09-03 15:55:37 +00:00
isContractCreation , homestead , istanbul ,
)
}
// intrinsic gas verification during CheckTx
if ctx . IsCheckTx ( ) && gasLimit < intrinsicGas {
2022-08-05 13:00:31 +00:00
return nil , 0 , sdkerrors . Wrapf (
2021-09-03 15:55:37 +00:00
sdkerrors . ErrOutOfGas ,
"gas limit too low: %d (gas limit) < %d (intrinsic gas)" , gasLimit , intrinsicGas ,
)
}
2021-12-15 02:17:03 +00:00
var feeAmt * big . Int
2021-10-04 14:58:06 +00:00
2022-08-05 13:00:31 +00:00
baseFee := k . getBaseFee ( ctx , london )
if baseFee != nil && txData . GetGasFeeCap ( ) . Cmp ( baseFee ) < 0 {
return nil , 0 , sdkerrors . Wrapf ( sdkerrors . ErrInsufficientFee , "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) " , txData . GetGasFeeCap ( ) , baseFee )
2021-10-04 14:58:06 +00:00
}
2022-08-05 13:00:31 +00:00
feeAmt = txData . EffectiveFee ( baseFee )
2022-01-26 10:44:41 +00:00
if feeAmt . Sign ( ) == 0 {
// zero fee, no need to deduct
2022-08-05 13:00:31 +00:00
return sdk . Coins { } , 0 , nil
2022-01-26 10:44:41 +00:00
}
2022-08-05 13:00:31 +00:00
fees = sdk . Coins { sdk . NewCoin ( denom , sdkmath . NewIntFromBigInt ( feeAmt ) ) }
2021-09-03 15:55:37 +00:00
// deduct the full gas cost from the user balance
2021-09-22 10:26:29 +00:00
if err := authante . DeductFees ( k . bankKeeper , ctx , signerAcc , fees ) ; err != nil {
2022-08-05 13:00:31 +00:00
return nil , 0 , sdkerrors . Wrapf (
2021-09-03 15:55:37 +00:00
err ,
"failed to deduct full gas cost %s from the user %s balance" ,
fees , msgEthTx . From ,
)
}
2022-08-05 13:00:31 +00:00
// calculate priority based on effective gas price
tipPrice := txData . EffectiveGasPrice ( baseFee )
// if london hardfork is not enabled, tipPrice is the gasPrice
if baseFee != nil {
tipPrice = new ( big . Int ) . Sub ( tipPrice , baseFee )
}
priorityBig := new ( big . Int ) . Quo ( tipPrice , DefaultPriorityReduction . BigInt ( ) )
if ! priorityBig . IsInt64 ( ) {
priority = math . MaxInt64
} else {
priority = priorityBig . Int64 ( )
}
return fees , priority , nil
2021-09-03 15:55:37 +00:00
}
2021-09-21 10:29:59 +00:00
// CheckSenderBalance validates that the tx cost value is positive and that the
// sender has enough funds to pay for the fees and value of the transaction.
2021-09-03 15:55:37 +00:00
func CheckSenderBalance (
2022-07-28 13:43:49 +00:00
balance sdkmath . Int ,
2021-09-03 15:55:37 +00:00
txData evmtypes . TxData ,
) error {
cost := txData . Cost ( )
2021-09-21 10:29:59 +00:00
if cost . Sign ( ) < 0 {
2021-11-26 14:19:28 +00:00
return sdkerrors . Wrapf (
sdkerrors . ErrInvalidCoins ,
2022-01-05 07:28:27 +00:00
"tx cost (%s) is negative and invalid" , cost ,
2021-11-26 14:19:28 +00:00
)
2021-09-21 10:29:59 +00:00
}
2022-01-05 07:28:27 +00:00
if balance . IsNegative ( ) || balance . BigInt ( ) . Cmp ( cost ) < 0 {
2021-11-26 14:19:28 +00:00
return sdkerrors . Wrapf (
sdkerrors . ErrInsufficientFunds ,
2022-01-05 07:28:27 +00:00
"sender balance < tx cost (%s < %s)" , balance , txData . Cost ( ) ,
2021-09-03 15:55:37 +00:00
)
}
return nil
}