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"
"github.com/palantir/stacktrace"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
2021-10-04 14:58:06 +00:00
cmath "github.com/ethereum/go-ethereum/common/math"
2021-09-03 15:55:37 +00:00
"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 {
return nil , stacktrace . Propagate ( err , "account not found for sender %s" , msgEthTx . From )
}
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 {
return nil , stacktrace . Propagate ( sdkerrors . Wrap (
err ,
"failed to compute intrinsic gas cost" ) , "failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t" ,
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-10-04 14:58:06 +00:00
// calculate the fees paid to validators based on the effective tip and price
effectiveTip := txData . GetGasPrice ( )
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-10-19 08:49:29 +00:00
gasFeeGap := new ( big . Int ) . Sub ( txData . GetGasFeeCap ( ) , baseFee )
if gasFeeGap . Sign ( ) == - 1 {
return nil , sdkerrors . Wrapf ( sdkerrors . ErrInsufficientFee , "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) " , txData . GetGasFeeCap ( ) , baseFee )
}
effectiveTip = cmath . BigMin ( txData . GetGasTipCap ( ) , gasFeeGap )
2021-10-04 14:58:06 +00:00
}
gasUsed := new ( big . Int ) . SetUint64 ( txData . GetGas ( ) )
feeAmt := new ( big . Int ) . Mul ( gasUsed , effectiveTip )
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-09-03 15:55:37 +00:00
return nil , stacktrace . Propagate (
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 (
ctx sdk . Context ,
bankKeeper evmtypes . BankKeeper ,
sender sdk . AccAddress ,
txData evmtypes . TxData ,
denom string ,
) error {
balance := bankKeeper . GetBalance ( ctx , sender , denom )
cost := txData . Cost ( )
2021-09-21 10:29:59 +00:00
if cost . Sign ( ) < 0 {
return stacktrace . Propagate (
sdkerrors . Wrapf (
sdkerrors . ErrInvalidCoins ,
"tx cost (%s%s) is negative and invalid" , cost , denom ,
) ,
"tx cost amount should never be negative" )
}
if balance . IsNegative ( ) || balance . Amount . BigInt ( ) . Cmp ( cost ) < 0 {
2021-09-03 15:55:37 +00:00
return stacktrace . Propagate (
sdkerrors . Wrapf (
sdkerrors . ErrInsufficientFunds ,
"sender balance < tx cost (%s < %s%s)" , balance , txData . Cost ( ) , denom ,
) ,
"sender should have had enough funds to pay for tx cost = fee + amount (%s = %s + %s)" ,
cost , txData . Fee ( ) , txData . GetValue ( ) ,
)
}
return nil
}