2021-09-03 15:55:37 +00:00
package keeper
import (
2021-10-04 14:58:06 +00:00
"math/big"
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"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
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 ,
2021-09-03 15:55:37 +00:00
) ( sdk . Coins , error ) {
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 {
2021-11-26 14:19:28 +00:00
return nil , 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 {
2021-11-26 14:19:28 +00:00
return nil , 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 {
return nil , sdkerrors . Wrapf (
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
feeMktParams := k . feeMarketKeeper . GetParams ( ctx )
2021-10-05 15:38:20 +00:00
if london && ! feeMktParams . NoBaseFee && txData . TxType ( ) == ethtypes . DynamicFeeTxType {
2021-10-04 14:58:06 +00:00
baseFee := k . feeMarketKeeper . GetBaseFee ( ctx )
2021-12-15 02:17:03 +00:00
if txData . GetGasFeeCap ( ) . Cmp ( baseFee ) < 0 {
2021-10-19 08:49:29 +00:00
return nil , sdkerrors . Wrapf ( sdkerrors . ErrInsufficientFee , "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) " , txData . GetGasFeeCap ( ) , baseFee )
}
2021-12-15 02:17:03 +00:00
feeAmt = txData . EffectiveFee ( baseFee )
} else {
feeAmt = txData . Fee ( )
2021-10-04 14:58:06 +00:00
}
2022-01-26 10:44:41 +00:00
if feeAmt . Sign ( ) == 0 {
// zero fee, no need to deduct
return sdk . NewCoins ( ) , nil
}
2021-09-03 15:55:37 +00:00
fees := sdk . Coins { sdk . NewCoin ( denom , sdk . NewIntFromBigInt ( feeAmt ) ) }
// 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 {
2021-11-26 14:19:28 +00:00
return nil , 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 ,
)
}
return fees , nil
}
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-01-05 07:28:27 +00:00
balance sdk . 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
}