From 15c6c78965bfc2e8461728c1232cb704ec148262 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sat, 12 Oct 2024 22:36:15 -0500 Subject: [PATCH 1/6] fix(gas-fees): use effective gas price in RefundGas --- .gitignore | 1 + CHANGELOG.md | 1 + app/evmante/evmante_can_transfer.go | 13 ++- app/evmante/evmante_gas_consume.go | 2 +- app/evmante/evmante_mempool_fees.go | 4 +- app/evmante/evmante_validate_basic.go | 4 +- app/evmante/interfaces.go | 2 +- e2e/evm/test/contract_send_nibi.test.ts | 20 +++- e2e/evm/test/native_transfer.test.ts | 5 +- eth/rpc/backend/backend.go | 6 +- eth/rpc/backend/tx_info.go | 2 +- justfile | 27 +++++ x/evm/const.go | 5 +- x/evm/keeper/gas_fees.go | 40 ++++--- x/evm/keeper/gas_fees_test.go | 143 ++++++++++++++++++++++++ x/evm/keeper/grpc_query.go | 13 ++- x/evm/keeper/keeper.go | 6 +- x/evm/keeper/msg_server.go | 10 +- x/evm/keeper/vm_config.go | 2 +- x/evm/msg.go | 11 +- x/evm/msg_test.go | 2 +- x/evm/statedb/config.go | 3 +- x/evm/tx.go | 2 +- x/evm/tx_data.go | 2 +- x/evm/tx_data_access_list.go | 11 +- x/evm/tx_data_dynamic_fee.go | 6 +- x/evm/tx_data_dynamic_fee_test.go | 2 +- x/evm/tx_data_legacy.go | 6 +- x/evm/tx_data_legacy_test.go | 2 +- 29 files changed, 275 insertions(+), 78 deletions(-) diff --git a/.gitignore b/.gitignore index 8e690b405..1906a076b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ txout.json vote.json **__pycache** scratch-paper.md +logs ### TypeScript and Friends diff --git a/CHANGELOG.md b/CHANGELOG.md index 7466f1bac..d178e715c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#2056](https://github.com/NibiruChain/nibiru/pull/2056) - feat(evm): add oracle precompile - [#2065](https://github.com/NibiruChain/nibiru/pull/2065) - refactor(evm)!: Refactor out dead code from the evm.Params - [#2073](https://github.com/NibiruChain/nibiru/pull/2073) - fix(evm-keeper): better utilize ERC20 metadata during FunToken creation +- [#2xxx](https://github.com/NibiruChain/nibiru/pull/2xxx) - fix(evm-gas-fees): fix(gas-fees): use effective gas price in RefundGas #### Dapp modules: perp, spot, oracle, etc diff --git a/app/evmante/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go index 6be462e3b..3315216d2 100644 --- a/app/evmante/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -44,9 +44,10 @@ func (ctd CanTransferDecorator) AnteHandle( "invalid message type %T, expected %T", msg, (*evm.MsgEthereumTx)(nil), ) } - baseFee := ctd.evmKeeper.GetBaseFee(ctx) + baseFeeMicronibiPerGas := ctd.evmKeeper.BaseFeeMicronibiPerGas(ctx) + baseFeeWeiPerGas := evm.NativeToWei(baseFeeMicronibiPerGas) - coreMsg, err := msgEthTx.AsMessage(signer, baseFee) + coreMsg, err := msgEthTx.AsMessage(signer, baseFeeWeiPerGas) if err != nil { return ctx, errors.Wrapf( err, @@ -54,17 +55,17 @@ func (ctd CanTransferDecorator) AnteHandle( ) } - if baseFee == nil { + if baseFeeMicronibiPerGas == nil { return ctx, errors.Wrap( evm.ErrInvalidBaseFee, "base fee is supported but evm block context value is nil", ) } - if coreMsg.GasFeeCap().Cmp(baseFee) < 0 { + if coreMsg.GasFeeCap().Cmp(baseFeeMicronibiPerGas) < 0 { return ctx, errors.Wrapf( sdkerrors.ErrInsufficientFee, "max fee per gas less than block base fee (%s < %s)", - coreMsg.GasFeeCap(), baseFee, + coreMsg.GasFeeCap(), baseFeeMicronibiPerGas, ) } @@ -73,7 +74,7 @@ func (ctd CanTransferDecorator) AnteHandle( ChainConfig: ethCfg, Params: params, CoinBase: gethcommon.Address{}, - BaseFee: baseFee, + BaseFee: baseFeeMicronibiPerGas, } stateDB := statedb.New( diff --git a/app/evmante/evmante_gas_consume.go b/app/evmante/evmante_gas_consume.go index cd58a17d0..e782c12ba 100644 --- a/app/evmante/evmante_gas_consume.go +++ b/app/evmante/evmante_gas_consume.go @@ -68,7 +68,7 @@ func (anteDec AnteDecEthGasConsume) AnteHandle( // Use the lowest priority of all the messages as the final one. minPriority := int64(math.MaxInt64) - baseFeeMicronibiPerGas := anteDec.evmKeeper.GetBaseFee(ctx) + baseFeeMicronibiPerGas := anteDec.evmKeeper.BaseFeeMicronibiPerGas(ctx) for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evm.MsgEthereumTx) diff --git a/app/evmante/evmante_mempool_fees.go b/app/evmante/evmante_mempool_fees.go index 0f27136ee..4f7bdd1a9 100644 --- a/app/evmante/evmante_mempool_fees.go +++ b/app/evmante/evmante_mempool_fees.go @@ -39,7 +39,7 @@ func (d MempoolGasPriceDecorator) AnteHandle( } minGasPrice := ctx.MinGasPrices().AmountOf(evm.EVMBankDenom) - baseFeeMicronibi := d.evmKeeper.GetBaseFee(ctx) + baseFeeMicronibi := d.evmKeeper.BaseFeeMicronibiPerGas(ctx) baseFeeDec := math.LegacyNewDecFromBigInt(baseFeeMicronibi) // if MinGasPrices is not set, skip the check @@ -61,7 +61,7 @@ func (d MempoolGasPriceDecorator) AnteHandle( baseFeeWei := evm.NativeToWei(baseFeeMicronibi) effectiveGasPriceDec := math.LegacyNewDecFromBigInt( - evm.WeiToNative(ethTx.GetEffectiveGasPrice(baseFeeWei)), + evm.WeiToNative(ethTx.EffectiveGasPriceWeiPerGas(baseFeeWei)), ) if effectiveGasPriceDec.LT(minGasPrice) { // if sdk.NewDecFromBigInt(effectiveGasPrice).LT(minGasPrice) { diff --git a/app/evmante/evmante_validate_basic.go b/app/evmante/evmante_validate_basic.go index 8db5a96b9..bc4dd5fa7 100644 --- a/app/evmante/evmante_validate_basic.go +++ b/app/evmante/evmante_validate_basic.go @@ -89,7 +89,7 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu txFee := sdk.Coins{} txGasLimit := uint64(0) - baseFee := vbd.evmKeeper.GetBaseFee(ctx) + baseFeeMicronibi := vbd.evmKeeper.BaseFeeMicronibiPerGas(ctx) for _, msg := range protoTx.GetMsgs() { msgEthTx, ok := msg.(*evm.MsgEthereumTx) @@ -115,7 +115,7 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu return ctx, errorsmod.Wrap(err, "failed to unpack MsgEthereumTx Data") } - if baseFee == nil && txData.TxType() == gethcore.DynamicFeeTxType { + if baseFeeMicronibi == nil && txData.TxType() == gethcore.DynamicFeeTxType { return ctx, errorsmod.Wrap( gethcore.ErrTxTypeNotSupported, "dynamic fee tx not supported", diff --git a/app/evmante/interfaces.go b/app/evmante/interfaces.go index 9c21b0412..2777ee464 100644 --- a/app/evmante/interfaces.go +++ b/app/evmante/interfaces.go @@ -27,7 +27,7 @@ type EVMKeeper interface { EVMState() evmkeeper.EvmState EthChainID(ctx sdk.Context) *big.Int - GetBaseFee(ctx sdk.Context) *big.Int + BaseFeeMicronibiPerGas(ctx sdk.Context) *big.Int } type protoTxProvider interface { diff --git a/e2e/evm/test/contract_send_nibi.test.ts b/e2e/evm/test/contract_send_nibi.test.ts index d820c9cd5..bbcec6459 100644 --- a/e2e/evm/test/contract_send_nibi.test.ts +++ b/e2e/evm/test/contract_send_nibi.test.ts @@ -10,7 +10,7 @@ * "e2e/evm/contracts/SendReceiveNibi.sol". */ import { describe, expect, it } from "@jest/globals" -import { toBigInt, Wallet } from "ethers" +import { parseEther, toBigInt, Wallet } from "ethers" import { account, provider } from "./setup" import { deployContractSendNibi } from "./utils" @@ -33,16 +33,24 @@ async function testSendNibi( const txCostWei = txCostMicronibi * tenPow12 const expectedOwnerWei = ownerBalanceBefore - txCostWei + const ownerBalanceAfter = await provider.getBalance(account) + const recipientBalanceAfter = await provider.getBalance(recipient) + console.debug(`DEBUG method ${method} %o:`, { ownerBalanceBefore, weiToSend, - gasUsed: receipt.gasUsed, - gasPrice: `${receipt.gasPrice.toString()} micronibi`, expectedOwnerWei, + ownerBalanceAfter, + recipientBalanceBefore, + recipientBalanceAfter, + gasUsed: receipt.gasUsed, + gasPrice: `${receipt.gasPrice.toString()}`, + to: receipt.to, + from: receipt.from, }) - - await expect(provider.getBalance(account)).resolves.toBe(expectedOwnerWei) - await expect(provider.getBalance(recipient)).resolves.toBe(weiToSend) + const deltaFromExpectation = ownerBalanceAfter - expectedOwnerWei + expect(deltaFromExpectation).toBeLessThan(parseEther("0.001")) + expect(recipientBalanceAfter).toBe(weiToSend) } describe("Send NIBI via smart contract", () => { diff --git a/e2e/evm/test/native_transfer.test.ts b/e2e/evm/test/native_transfer.test.ts index d25ef4cc9..4b3c098c2 100644 --- a/e2e/evm/test/native_transfer.test.ts +++ b/e2e/evm/test/native_transfer.test.ts @@ -26,7 +26,7 @@ describe("native transfer", () => { // Assert balances with logging const tenPow12 = toBigInt(1e12) - const gasUsed = 50000n // 50k gas for the transaction + const gasUsed = transaction.gasLimit const txCostMicronibi = amountToSend / tenPow12 + gasUsed const txCostWei = txCostMicronibi * tenPow12 const expectedSenderWei = senderBalanceBefore - txCostWei @@ -35,8 +35,9 @@ describe("native transfer", () => { amountToSend, expectedSenderWei, senderBalanceAfter, + txResponse, }) - expect(senderBalanceAfter).toEqual(expectedSenderWei) expect(recipientBalanceAfter).toEqual(amountToSend) + expect(senderBalanceAfter).toEqual(expectedSenderWei) }, 20e3) }) diff --git a/eth/rpc/backend/backend.go b/eth/rpc/backend/backend.go index c8bebb610..047692b09 100644 --- a/eth/rpc/backend/backend.go +++ b/eth/rpc/backend/backend.go @@ -60,7 +60,7 @@ func NewBackend( // TODO: feat(eth): Implement the cosmos JSON-RPC defined by Wallet Connect V2: // https://docs.walletconnect.com/2.0/json-rpc/cosmos. type CosmosBackend interface { - // TODO: GetAccounts() - // TODO: SignDirect() - // TODO: SignAmino() + // TODO: for Wallet Connect V2: GetAccounts() + // TODO: for Wallet Connect V2: SignDirect() + // TODO: for Wallet Connect V2: SignAmino() } diff --git a/eth/rpc/backend/tx_info.go b/eth/rpc/backend/tx_info.go index 8d4569d16..a8cb127b0 100644 --- a/eth/rpc/backend/tx_info.go +++ b/eth/rpc/backend/tx_info.go @@ -253,7 +253,7 @@ func (b *Backend) GetTransactionReceipt(hash gethcommon.Hash) (*TransactionRecei // tolerate the error for pruned node. b.logger.Error("fetch basefee failed, node is pruned?", "height", res.Height, "error", err) } else { - receipt.EffectiveGasPrice = dynamicTx.EffectiveGasPriceWei(baseFee) + receipt.EffectiveGasPrice = dynamicTx.EffectiveGasPriceWeiPerGas(baseFee) } } return &receipt, nil diff --git a/justfile b/justfile index fbdcef302..9a3bddca7 100644 --- a/justfile +++ b/justfile @@ -47,6 +47,33 @@ lint: localnet *PASS_FLAGS: make localnet FLAGS="{{PASS_FLAGS}}" +# Clears the logs directory +log-clear: + #!/usr/bin/env bash + rm logs/* + +# Runs "just localnet" with logging (logs/localnet.txt) +log-localnet: + #!/usr/bin/env bash + mkdir -p logs + just localnet 2>&1 | tee -a logs/localnet.txt + +# Runs the EVM E2E test with logging (logs/e2e.txt) +log-e2e: + #!/usr/bin/env bash + just test-e2e 2>&1 | tee -a ../../logs/e2e.txt + +# Runs the EVM E2E tests +test-e2e: + #!/usr/bin/env bash + source contrib/bashlib.sh + log_info "Make sure the localnet is running! (just localnet)" + + cd e2e/evm + nvm use + just test + + # Test: "localnet.sh" script test-localnet: #!/usr/bin/env bash diff --git a/x/evm/const.go b/x/evm/const.go index b8302100e..1ddf8e67d 100644 --- a/x/evm/const.go +++ b/x/evm/const.go @@ -12,7 +12,10 @@ import ( // BASE_FEE_MICRONIBI is the global base fee value for the network. It has a // constant value of 1 unibi (micronibi) == 10^12 wei. -var BASE_FEE_MICRONIBI = big.NewInt(1) +var ( + BASE_FEE_MICRONIBI = big.NewInt(1) + BASE_FEE_WEI = NativeToWei(BASE_FEE_MICRONIBI) +) const ( // ModuleName string name of module diff --git a/x/evm/keeper/gas_fees.go b/x/evm/keeper/gas_fees.go index e33fc7f09..aff670907 100644 --- a/x/evm/keeper/gas_fees.go +++ b/x/evm/keeper/gas_fees.go @@ -34,36 +34,42 @@ func (k *Keeper) GetEthIntrinsicGas( ) } -// RefundGas transfers the leftover gas to the sender of the message, caped to -// half of the total gas consumed in the transaction. Additionally, the function -// sets the total gas consumed to the value returned by the EVM execution, thus -// ignoring the previous intrinsic gas consumed during in the AnteHandler. +// RefundGas transfers the leftover gas to the sender of the message. func (k *Keeper) RefundGas( ctx sdk.Context, - msg core.Message, + msgFrom gethcommon.Address, leftoverGas uint64, - denom string, + weiPerGas *big.Int, ) error { // Return EVM tokens for remaining gas, exchanged at the original rate. - remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice()) + leftoverWei := new(big.Int).Mul( + new(big.Int).SetUint64(leftoverGas), + weiPerGas, + ) + leftoverMicronibi := evm.WeiToNative(leftoverWei) - switch remaining.Sign() { + switch leftoverMicronibi.Sign() { case -1: - // negative refund errors - return errors.Wrapf(evm.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64()) + // Should be impossible since leftoverGas is a uint64. Reaching this case + // would imply a critical error in the effective gas calculation. + return errors.Wrapf(evm.ErrInvalidRefund, "refunded amount value cannot be negative %d", leftoverMicronibi.Int64()) case 1: - // positive amount refund - refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(remaining))} - - // refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees - - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins) + refundedCoins := sdk.Coins{sdk.NewCoin(evm.EVMBankDenom, sdkmath.NewIntFromBigInt(leftoverMicronibi))} + + // Refund to sender from the fee collector module account. This account + // manages the collection of gas fees. + err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, + authtypes.FeeCollectorName, // sender + msgFrom.Bytes(), // recipient + refundedCoins, + ) if err != nil { err = errors.Wrapf(errortypes.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) return errors.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) } default: - // no refund, consume gas and update the tx gas meter + // no refund } return nil diff --git a/x/evm/keeper/gas_fees_test.go b/x/evm/keeper/gas_fees_test.go index efefff44c..2afd9beec 100644 --- a/x/evm/keeper/gas_fees_test.go +++ b/x/evm/keeper/gas_fees_test.go @@ -4,10 +4,15 @@ package keeper_test import ( "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" + auth "github.com/cosmos/cosmos-sdk/x/auth/types" + gethcommon "github.com/ethereum/go-ethereum/common" gethparams "github.com/ethereum/go-ethereum/params" + "cosmossdk.io/math" sdkmath "cosmossdk.io/math" + "github.com/NibiruChain/nibiru/v2/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/v2/x/evm" "github.com/NibiruChain/nibiru/v2/x/evm/evmtest" evmkeeper "github.com/NibiruChain/nibiru/v2/x/evm/keeper" @@ -112,3 +117,141 @@ func (s *Suite) TestVerifyFee() { }) } } + +// TestRefundGas: Verifies that `Keeper.RefundGas` refunds properly with +// different values of effective gas price (weiPerGas) and fee collector balances. +func (s *Suite) TestRefundGas() { + type testCase struct { + name string + msgFrom gethcommon.Address + leftoverGas uint64 + // Comes from EffectiveGasPriceWeiPerGas + weiPerGas *big.Int + // (Optional) Expected error message that occurs from RefundGas + wantErr string + // refund amount is leftoverGas * weiPerGas * micronibiPerWei + wantRefundAmt *big.Int + } + + feeCollectorInitialBalance := big.NewInt(40_000) + fundFeeCollectorEvmBal := func(deps *evmtest.TestDeps, s *Suite, bal *big.Int) { + err := testapp.FundModuleAccount( + deps.App.BankKeeper, deps.Ctx, auth.FeeCollectorName, + sdk.NewCoins(sdk.NewCoin( + evm.EVMBankDenom, math.NewIntFromBigInt(bal), + )), + ) + s.Require().NoError(err) + } + + for _, getTestCase := range []func(deps *evmtest.TestDeps) testCase{ + func(deps *evmtest.TestDeps) testCase { + fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) + return testCase{ + name: "happy: geth tx gas, base fee normal", + msgFrom: deps.Sender.EthAddr, + leftoverGas: gethparams.TxGas, + weiPerGas: evm.BASE_FEE_WEI, + wantErr: "", + wantRefundAmt: new(big.Int).SetUint64(gethparams.TxGas), + } + }, + func(deps *evmtest.TestDeps) testCase { + fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) + return testCase{ + name: "happy: minimum wei per gas -> 0 refund", + msgFrom: deps.Sender.EthAddr, + leftoverGas: gethparams.TxGas, + weiPerGas: big.NewInt(1), + wantErr: "", + wantRefundAmt: new(big.Int).SetUint64(0), + } + }, + func(deps *evmtest.TestDeps) testCase { + fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) + return testCase{ + name: "happy: wei per gas slightly below default base fee", + msgFrom: deps.Sender.EthAddr, + leftoverGas: gethparams.TxGas, + weiPerGas: new(big.Int).Sub(evm.BASE_FEE_WEI, big.NewInt(1)), + wantErr: "", + wantRefundAmt: new(big.Int).SetUint64(20_999), + } + }, + func(deps *evmtest.TestDeps) testCase { + fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) + return testCase{ + name: "happy: wei per gas 10% of default base fee", + msgFrom: deps.Sender.EthAddr, + leftoverGas: gethparams.TxGas, + weiPerGas: new(big.Int).Quo(evm.BASE_FEE_WEI, big.NewInt(10)), + wantErr: "", + wantRefundAmt: new(big.Int).SetUint64(2100), + } + }, + func(deps *evmtest.TestDeps) testCase { + // fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) + return testCase{ + name: "sad: geth tx gas, base fee normal, fee collector is broke", + msgFrom: deps.Sender.EthAddr, + leftoverGas: gethparams.TxGas, + weiPerGas: evm.BASE_FEE_WEI, + wantErr: "failed to refund 21000 leftover gas (21000unibi)", + } + }, + func(deps *evmtest.TestDeps) testCase { + fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) + return testCase{ + name: "sad: geth tx gas, negative ?? base fee (impossible but here for compelteness", + msgFrom: deps.Sender.EthAddr, + leftoverGas: gethparams.TxGas, + weiPerGas: new(big.Int).Neg(evm.BASE_FEE_WEI), + wantErr: evm.ErrInvalidRefund.Error(), + } + }, + } { + deps := evmtest.NewTestDeps() + tc := getTestCase(&deps) + s.Run(tc.name, func() { + fromBalBefore := deps.App.BankKeeper.GetBalance( + deps.Ctx, deps.Sender.NibiruAddr, evm.EVMBankDenom, + ).Amount.BigInt() + feeCollectorBalBefore := deps.App.BankKeeper.GetBalance( + deps.Ctx, + auth.NewModuleAddress(auth.FeeCollectorName), + evm.EVMBankDenom, + ).Amount.BigInt() + + err := deps.EvmKeeper.RefundGas( + deps.Ctx, tc.msgFrom, tc.leftoverGas, tc.weiPerGas, + ) + if tc.wantErr != "" { + s.Require().ErrorContains(err, tc.wantErr) + return + } + s.Require().NoError(err) + + // refund amount is leftoverGas * weiPerGas * micronibiPerWei + // msgFrom should have balance + fromBalAfter := deps.App.BankKeeper.GetBalance( + deps.Ctx, deps.Sender.NibiruAddr, evm.EVMBankDenom, + ).Amount.BigInt() + feeCollectorBalAfter := deps.App.BankKeeper.GetBalance( + deps.Ctx, + auth.NewModuleAddress(auth.FeeCollectorName), + evm.EVMBankDenom, + ).Amount.BigInt() + + s.Equal( + new(big.Int).Sub(fromBalAfter, fromBalBefore).String(), + tc.wantRefundAmt.String(), + "sender balance did not get refunded as expected", + ) + s.Equal( + new(big.Int).Sub(feeCollectorBalAfter, feeCollectorBalBefore).String(), + new(big.Int).Neg(tc.wantRefundAmt).String(), + "fee collector did not refund as expected", + ) + }) + } +} diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index c2c051be3..154066d72 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -144,9 +144,10 @@ func (k Keeper) BaseFee( goCtx context.Context, _ *evm.QueryBaseFeeRequest, ) (*evm.QueryBaseFeeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - baseFee := sdkmath.NewIntFromBigInt(k.GetBaseFee(ctx)) + baseFee := sdkmath.NewIntFromBigInt(k.BaseFeeMicronibiPerGas(ctx)) return &evm.QueryBaseFeeResponse{ BaseFee: &baseFee, + // TODO: Show both units }, nil } @@ -489,7 +490,7 @@ func (k Keeper) TraceTx( } // compute and use base fee of the height that is being traced - baseFee := k.GetBaseFee(ctx) + baseFee := k.BaseFeeMicronibiPerGas(ctx) if baseFee != nil { cfg.BaseFee = baseFee } @@ -588,9 +589,9 @@ func (k Keeper) TraceCall( } // compute and use base fee of the height that is being traced - baseFee := k.GetBaseFee(ctx) - if baseFee != nil { - cfg.BaseFee = baseFee + baseFeeMicronibi := k.BaseFeeMicronibiPerGas(ctx) + if baseFeeMicronibi != nil { + cfg.BaseFee = baseFeeMicronibi } txConfig := statedb.NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes())) @@ -677,7 +678,7 @@ func (k Keeper) TraceBlock( } // compute and use base fee of height that is being traced - baseFee := k.GetBaseFee(ctx) + baseFee := k.BaseFeeMicronibiPerGas(ctx) if baseFee != nil { cfg.BaseFee = baseFee } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index d86b1a36d..f0d18c765 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -114,9 +114,9 @@ func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) math.LegacyDec { return math.LegacyNewDecWithPrec(50, 2) // 50% } -// GetBaseFee returns the gas base fee in units of the EVM denom. Note that this -// function is currently constant/stateless. -func (k Keeper) GetBaseFee(_ sdk.Context) *big.Int { +// BaseFeeMicronibiPerGas returns the gas base fee in units of the EVM denom. Note +// that this function is currently constant/stateless. +func (k Keeper) BaseFeeMicronibiPerGas(_ sdk.Context) *big.Int { // TODO: (someday maybe): Consider making base fee dynamic based on // congestion in the previous block. return evm.BASE_FEE_MICRONIBI diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 3eaf8bd44..b86e572e7 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -35,9 +35,8 @@ func (k *Keeper) EthereumTx( return resp, errors.Wrap(err, "EthereumTx validate basic failed") } ctx := sdk.UnwrapSDKContext(goCtx) - tx := msg.AsTransaction() - resp, err = k.ApplyEvmTx(ctx, tx) + resp, err = k.ApplyEvmTx(ctx, msg) if err != nil { return nil, errors.Wrap(err, "failed to apply transaction") } @@ -45,8 +44,10 @@ func (k *Keeper) EthereumTx( } func (k *Keeper) ApplyEvmTx( - ctx sdk.Context, tx *gethcore.Transaction, + ctx sdk.Context, txMsg *evm.MsgEthereumTx, ) (*evm.MsgEthereumTxResponse, error) { + tx := txMsg.AsTransaction() + evmConfig, err := k.GetEVMConfig(ctx, ctx.BlockHeader().ProposerAddress, k.EthChainID(ctx)) if err != nil { return nil, errors.Wrap(err, "failed to load evm config") @@ -111,7 +112,8 @@ func (k *Keeper) ApplyEvmTx( if msg.Gas() > evmResp.GasUsed { refundGas = msg.Gas() - evmResp.GasUsed } - if err = k.RefundGas(ctx, msg, refundGas, evm.EVMBankDenom); err != nil { + weiPerGas := txMsg.EffectiveGasPriceWeiPerGas(evmConfig.BaseFee) + if err = k.RefundGas(ctx, msg.From(), refundGas, weiPerGas); err != nil { return nil, errors.Wrapf(err, "failed to refund leftover gas to sender %s", msg.From()) } diff --git a/x/evm/keeper/vm_config.go b/x/evm/keeper/vm_config.go index ca62b416c..10f7c14d7 100644 --- a/x/evm/keeper/vm_config.go +++ b/x/evm/keeper/vm_config.go @@ -27,7 +27,7 @@ func (k *Keeper) GetEVMConfig( return nil, errors.Wrap(err, "failed to obtain coinbase address") } - baseFee := k.GetBaseFee(ctx) + baseFee := k.BaseFeeMicronibiPerGas(ctx) return &statedb.EVMConfig{ Params: params, ChainConfig: ethCfg, diff --git a/x/evm/msg.go b/x/evm/msg.go index f27cade13..3ab4ff024 100644 --- a/x/evm/msg.go +++ b/x/evm/msg.go @@ -267,8 +267,8 @@ func (msg MsgEthereumTx) GetFee() *big.Int { return txData.Fee() } -// GetEffectiveFee returns the fee for dynamic fee tx -func (msg MsgEthereumTx) GetEffectiveFee(baseFee *big.Int) *big.Int { +// EffectiveFeeWei returns the fee for dynamic fee tx +func (msg MsgEthereumTx) EffectiveFeeWei(baseFee *big.Int) *big.Int { txData, err := UnpackTxData(msg.Data) if err != nil { return nil @@ -276,13 +276,14 @@ func (msg MsgEthereumTx) GetEffectiveFee(baseFee *big.Int) *big.Int { return txData.EffectiveFeeWei(baseFee) } -// GetEffectiveFee returns the fee for dynamic fee tx -func (msg MsgEthereumTx) GetEffectiveGasPrice(baseFeeWei *big.Int) *big.Int { +// EffectiveGasPriceWeiPerGas returns the effective gas price according to the base +// fee. This value is in units of "wei per unit gas". +func (msg MsgEthereumTx) EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.Int { txData, err := UnpackTxData(msg.Data) if err != nil { return nil } - return txData.EffectiveGasPriceWei(baseFeeWei) + return txData.EffectiveGasPriceWeiPerGas(baseFeeWei) } // GetFrom loads the ethereum sender address from the sigcache and returns an diff --git a/x/evm/msg_test.go b/x/evm/msg_test.go index e9b8533ba..e51c2b9a3 100644 --- a/x/evm/msg_test.go +++ b/x/evm/msg_test.go @@ -698,7 +698,7 @@ func (s *MsgsSuite) TestMsgEthereumTx_Getters() { fee = tx.GetFee() s.Require().Equal(tc.exp, fee) case strings.Contains(tc.name, "get effective fee"): - effFee = tx.GetEffectiveFee(big.NewInt(0)) + effFee = tx.EffectiveFeeWei(big.NewInt(0)) s.Require().Equal(tc.exp, effFee) case strings.Contains(tc.name, "get gas"): gas := tx.GetGas() diff --git a/x/evm/statedb/config.go b/x/evm/statedb/config.go index f29385fa5..a4d5a29d0 100644 --- a/x/evm/statedb/config.go +++ b/x/evm/statedb/config.go @@ -45,5 +45,6 @@ type EVMConfig struct { Params evm.Params ChainConfig *params.ChainConfig CoinBase common.Address - BaseFee *big.Int + // BaseFee is the EVM base fee in units of micronibi per gas + BaseFee *big.Int } diff --git a/x/evm/tx.go b/x/evm/tx.go index f710def67..ba409a855 100644 --- a/x/evm/tx.go +++ b/x/evm/tx.go @@ -39,7 +39,7 @@ var DefaultPriorityReduction = sdk.DefaultPowerReduction // tx_priority = tip_price / priority_reduction func GetTxPriority(txData TxData, baseFee *big.Int) (priority int64) { // calculate priority based on effective gas price - tipPrice := txData.EffectiveGasPriceWei(baseFee) + tipPrice := txData.EffectiveGasPriceWeiPerGas(baseFee) // Return the min of the max possible priorty and the derived priority priority = math.MaxInt64 diff --git a/x/evm/tx_data.go b/x/evm/tx_data.go index 979dcd72f..f7b47f22b 100644 --- a/x/evm/tx_data.go +++ b/x/evm/tx_data.go @@ -91,7 +91,7 @@ type TxData interface { Cost() *big.Int // effective gasPrice/fee/cost according to current base fee - EffectiveGasPriceWei(baseFeeWei *big.Int) *big.Int + EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.Int EffectiveFeeWei(baseFeeWei *big.Int) *big.Int EffectiveCost(baseFeeWei *big.Int) *big.Int } diff --git a/x/evm/tx_data_access_list.go b/x/evm/tx_data_access_list.go index 19ccaa488..82adcbeda 100644 --- a/x/evm/tx_data_access_list.go +++ b/x/evm/tx_data_access_list.go @@ -286,18 +286,19 @@ func (tx AccessListTx) Cost() *big.Int { return cost(tx.Fee(), tx.GetValueWei()) } -// EffectiveGasPriceWei is the same as GasPrice for AccessListTx -func (tx AccessListTx) EffectiveGasPriceWei(baseFeeWei *big.Int) *big.Int { +// EffectiveGasPriceWeiPerGas is the same as GasPrice for AccessListTx +func (tx AccessListTx) EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.Int { return BigIntMax(tx.GetGasPrice(), baseFeeWei) } // EffectiveFeeWei is the same as Fee for AccessListTx func (tx AccessListTx) EffectiveFeeWei(baseFeeWei *big.Int) *big.Int { - return priceTimesGas(tx.EffectiveGasPriceWei(baseFeeWei), tx.GetGas()) + return priceTimesGas(tx.EffectiveGasPriceWeiPerGas(baseFeeWei), tx.GetGas()) } // EffectiveCost is the same as Cost for AccessListTx func (tx AccessListTx) EffectiveCost(baseFeeWei *big.Int) *big.Int { - txFee := tx.EffectiveFeeWei(baseFeeWei) - return cost(txFee, tx.GetValueWei()) + return cost( + tx.EffectiveFeeWei(baseFeeWei), tx.GetValueWei(), + ) } diff --git a/x/evm/tx_data_dynamic_fee.go b/x/evm/tx_data_dynamic_fee.go index 81797617b..7f710a70a 100644 --- a/x/evm/tx_data_dynamic_fee.go +++ b/x/evm/tx_data_dynamic_fee.go @@ -291,9 +291,9 @@ func (tx DynamicFeeTx) Cost() *big.Int { return cost(tx.Fee(), tx.GetValueWei()) } -// EffectiveGasPriceWei returns the effective gas price based on EIP-1559 rules. +// EffectiveGasPriceWeiPerGas returns the effective gas price based on EIP-1559 rules. // `effectiveGasPrice = min(baseFee + tipCap, feeCap)` -func (tx *DynamicFeeTx) EffectiveGasPriceWei(baseFeeWei *big.Int) *big.Int { +func (tx *DynamicFeeTx) EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.Int { feeWithSpecifiedTip := new(big.Int).Add(tx.GasTipCap.BigInt(), baseFeeWei) // Enforce base fee as the minimum [EffectiveGasPriceWei]: @@ -303,7 +303,7 @@ func (tx *DynamicFeeTx) EffectiveGasPriceWei(baseFeeWei *big.Int) *big.Int { // EffectiveFeeWei returns effective_gasprice * gaslimit. func (tx DynamicFeeTx) EffectiveFeeWei(baseFeeWei *big.Int) *big.Int { - return priceTimesGas(tx.EffectiveGasPriceWei(baseFeeWei), tx.GasLimit) + return priceTimesGas(tx.EffectiveGasPriceWeiPerGas(baseFeeWei), tx.GasLimit) } // EffectiveCost returns amount + effective_gasprice * gaslimit. diff --git a/x/evm/tx_data_dynamic_fee_test.go b/x/evm/tx_data_dynamic_fee_test.go index ec2b5d579..f9b73ecce 100644 --- a/x/evm/tx_data_dynamic_fee_test.go +++ b/x/evm/tx_data_dynamic_fee_test.go @@ -610,7 +610,7 @@ func (suite *Suite) TestDynamicFeeTxEffectiveGasPrice() { for _, tc := range testCases { txData := tc.tx() - actual := txData.EffectiveGasPriceWei(tc.baseFeeWei) + actual := txData.EffectiveGasPriceWeiPerGas(tc.baseFeeWei) suite.Require().Equal(tc.exp, actual, tc.name) } diff --git a/x/evm/tx_data_legacy.go b/x/evm/tx_data_legacy.go index 6a1baea30..efa3f9d57 100644 --- a/x/evm/tx_data_legacy.go +++ b/x/evm/tx_data_legacy.go @@ -190,14 +190,14 @@ func (tx LegacyTx) Cost() *big.Int { return cost(tx.Fee(), tx.GetValueWei()) } -// EffectiveGasPriceWei is the same as GasPrice for LegacyTx -func (tx LegacyTx) EffectiveGasPriceWei(baseFeeWei *big.Int) *big.Int { +// EffectiveGasPriceWeiPerGas is the same as GasPrice for LegacyTx +func (tx LegacyTx) EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.Int { return BigIntMax(tx.GetGasPrice(), baseFeeWei) } // EffectiveFeeWei is the same as Fee for LegacyTx func (tx LegacyTx) EffectiveFeeWei(baseFeeWei *big.Int) *big.Int { - return priceTimesGas(tx.EffectiveGasPriceWei(baseFeeWei), tx.GetGas()) + return priceTimesGas(tx.EffectiveGasPriceWeiPerGas(baseFeeWei), tx.GetGas()) } // EffectiveCost is the same as Cost for LegacyTx diff --git a/x/evm/tx_data_legacy_test.go b/x/evm/tx_data_legacy_test.go index 6b81152cf..85f83df4f 100644 --- a/x/evm/tx_data_legacy_test.go +++ b/x/evm/tx_data_legacy_test.go @@ -372,7 +372,7 @@ func (suite *Suite) TestLegacyTxEffectiveGasPrice() { } for _, tc := range testCases { - actual := tc.tx.EffectiveGasPriceWei(tc.baseFee) + actual := tc.tx.EffectiveGasPriceWeiPerGas(tc.baseFee) suite.Require().Equal(tc.exp, actual, tc.name) } From a347a72b81c982258f9ee69a47dbe86ce24167b9 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 13 Oct 2024 00:07:13 -0500 Subject: [PATCH 2/6] Add even more unit clarity for base fee and delete code --- CHANGELOG.md | 5 +- app/evmante/evmante_can_transfer.go | 27 +-- app/evmante/evmante_can_transfer_test.go | 2 +- app/evmante/evmante_emit_event.go | 4 +- app/evmante/evmante_gas_consume.go | 4 +- app/evmante/evmante_handler.go | 2 +- app/evmante/evmante_increment_sender_seq.go | 4 +- app/evmante/evmante_mempool_fees.go | 10 +- app/evmante/evmante_setup_ctx.go | 4 +- app/evmante/evmante_sigverify.go | 4 +- app/evmante/evmante_validate_basic.go | 4 +- app/evmante/evmante_verify_eth_acc.go | 4 +- app/evmante/interfaces.go | 26 +- eth/rpc/backend/blocks.go | 14 +- eth/rpc/backend/chain_info.go | 11 +- eth/rpc/backend/chain_info_test.go | 4 +- eth/rpc/backend/tx_info.go | 12 +- eth/rpc/backend/utils.go | 2 +- eth/rpc/rpc.go | 8 +- eth/rpc/rpcapi/websockets.go | 4 +- proto/eth/evm/v1/query.proto | 10 +- x/evm/json_tx_args.go | 6 +- x/evm/keeper/grpc_query.go | 33 +-- x/evm/keeper/grpc_query_test.go | 6 +- x/evm/keeper/keeper.go | 4 +- x/evm/keeper/msg_server.go | 8 +- x/evm/keeper/vm_config.go | 14 +- x/evm/query.pb.go | 254 ++++++++++++-------- x/evm/statedb/config.go | 38 +-- x/evm/tx_data_dynamic_fee_test.go | 6 +- 30 files changed, 291 insertions(+), 243 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d178e715c..45c9f61da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,7 +129,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#2056](https://github.com/NibiruChain/nibiru/pull/2056) - feat(evm): add oracle precompile - [#2065](https://github.com/NibiruChain/nibiru/pull/2065) - refactor(evm)!: Refactor out dead code from the evm.Params - [#2073](https://github.com/NibiruChain/nibiru/pull/2073) - fix(evm-keeper): better utilize ERC20 metadata during FunToken creation -- [#2xxx](https://github.com/NibiruChain/nibiru/pull/2xxx) - fix(evm-gas-fees): fix(gas-fees): use effective gas price in RefundGas +- [#2076](https://github.com/NibiruChain/nibiru/pull/2076) - fix(evm-gas-fees): +Use effective gas price in RefundGas and make sure that units are properly +reflected on all occurences of "base fee" in the codebase. This fixes [#2059](https://github.com/NibiruChain/nibiru/issues/2059) +and the [related comments from @Unique-Divine and @berndartmueller](https://github.com/NibiruChain/nibiru/issues/2059#issuecomment-2408625724). #### Dapp modules: perp, spot, oracle, etc diff --git a/app/evmante/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go index 3315216d2..cb271e36a 100644 --- a/app/evmante/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -17,14 +17,7 @@ import ( // CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block // context rules. type CanTransferDecorator struct { - evmKeeper EVMKeeper -} - -// NewCanTransferDecorator creates a new CanTransferDecorator instance. -func NewCanTransferDecorator(k EVMKeeper) CanTransferDecorator { - return CanTransferDecorator{ - evmKeeper: k, - } + *EVMKeeper } // AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to @@ -32,8 +25,8 @@ func NewCanTransferDecorator(k EVMKeeper) CanTransferDecorator { func (ctd CanTransferDecorator) AnteHandle( ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler, ) (sdk.Context, error) { - params := ctd.evmKeeper.GetParams(ctx) - ethCfg := evm.EthereumConfig(ctd.evmKeeper.EthChainID(ctx)) + params := ctd.GetParams(ctx) + ethCfg := evm.EthereumConfig(ctd.EVMKeeper.EthChainID(ctx)) signer := gethcore.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight())) for _, msg := range tx.GetMsgs() { @@ -44,7 +37,7 @@ func (ctd CanTransferDecorator) AnteHandle( "invalid message type %T, expected %T", msg, (*evm.MsgEthereumTx)(nil), ) } - baseFeeMicronibiPerGas := ctd.evmKeeper.BaseFeeMicronibiPerGas(ctx) + baseFeeMicronibiPerGas := ctd.EVMKeeper.BaseFeeMicronibiPerGas(ctx) baseFeeWeiPerGas := evm.NativeToWei(baseFeeMicronibiPerGas) coreMsg, err := msgEthTx.AsMessage(signer, baseFeeWeiPerGas) @@ -71,18 +64,18 @@ func (ctd CanTransferDecorator) AnteHandle( // NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below cfg := &statedb.EVMConfig{ - ChainConfig: ethCfg, - Params: params, - CoinBase: gethcommon.Address{}, - BaseFee: baseFeeMicronibiPerGas, + ChainConfig: ethCfg, + Params: params, + BlockCoinbase: gethcommon.Address{}, + BaseFeeWei: baseFeeMicronibiPerGas, } stateDB := statedb.New( ctx, - ctd.evmKeeper, + ctd.EVMKeeper, statedb.NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes())), ) - evmInstance := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evm.NewNoOpTracer(), stateDB) + evmInstance := ctd.EVMKeeper.NewEVM(ctx, coreMsg, cfg, evm.NewNoOpTracer(), stateDB) // check that caller has enough balance to cover asset transfer for **topmost** call // NOTE: here the gas consumed is from the context with the infinite gas meter diff --git a/app/evmante/evmante_can_transfer_test.go b/app/evmante/evmante_can_transfer_test.go index 74e697f8b..2fa71c674 100644 --- a/app/evmante/evmante_can_transfer_test.go +++ b/app/evmante/evmante_can_transfer_test.go @@ -89,7 +89,7 @@ func (s *TestSuite) TestCanTransferDecorator() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := evmante.NewCanTransferDecorator(&deps.App.AppKeepers.EvmKeeper) + anteDec := evmante.CanTransferDecorator{&deps.App.AppKeepers.EvmKeeper} tx := tc.txSetup(&deps) if tc.ctxSetup != nil { diff --git a/app/evmante/evmante_emit_event.go b/app/evmante/evmante_emit_event.go index a9c656284..d9cc579db 100644 --- a/app/evmante/evmante_emit_event.go +++ b/app/evmante/evmante_emit_event.go @@ -13,11 +13,11 @@ import ( // EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit). type EthEmitEventDecorator struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper } // NewEthEmitEventDecorator creates a new EthEmitEventDecorator -func NewEthEmitEventDecorator(k EVMKeeper) EthEmitEventDecorator { +func NewEthEmitEventDecorator(k *EVMKeeper) EthEmitEventDecorator { return EthEmitEventDecorator{ evmKeeper: k, } diff --git a/app/evmante/evmante_gas_consume.go b/app/evmante/evmante_gas_consume.go index e782c12ba..a10ad8f2f 100644 --- a/app/evmante/evmante_gas_consume.go +++ b/app/evmante/evmante_gas_consume.go @@ -17,13 +17,13 @@ import ( // AnteDecEthGasConsume validates enough intrinsic gas for the transaction and // gas consumption. type AnteDecEthGasConsume struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper maxGasWanted uint64 } // NewAnteDecEthGasConsume creates a new EthGasConsumeDecorator func NewAnteDecEthGasConsume( - k EVMKeeper, + k *EVMKeeper, maxGasWanted uint64, ) AnteDecEthGasConsume { return AnteDecEthGasConsume{ diff --git a/app/evmante/evmante_handler.go b/app/evmante/evmante_handler.go index f7fb5ba17..787be312e 100644 --- a/app/evmante/evmante_handler.go +++ b/app/evmante/evmante_handler.go @@ -18,7 +18,7 @@ func NewAnteHandlerEVM( NewEthValidateBasicDecorator(&options.EvmKeeper), NewEthSigVerificationDecorator(&options.EvmKeeper), NewAnteDecVerifyEthAcc(&options.EvmKeeper, options.AccountKeeper), - NewCanTransferDecorator(&options.EvmKeeper), + CanTransferDecorator{&options.EvmKeeper}, NewAnteDecEthGasConsume(&options.EvmKeeper, options.MaxTxGasWanted), NewAnteDecEthIncrementSenderSequence(&options.EvmKeeper, options.AccountKeeper), ante.AnteDecoratorGasWanted{}, diff --git a/app/evmante/evmante_increment_sender_seq.go b/app/evmante/evmante_increment_sender_seq.go index 2dfa54429..88abaf2e3 100644 --- a/app/evmante/evmante_increment_sender_seq.go +++ b/app/evmante/evmante_increment_sender_seq.go @@ -13,12 +13,12 @@ import ( // AnteDecEthIncrementSenderSequence increments the sequence of the signers. type AnteDecEthIncrementSenderSequence struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper accountKeeper ante.AccountKeeper } // NewAnteDecEthIncrementSenderSequence creates a new EthIncrementSenderSequenceDecorator. -func NewAnteDecEthIncrementSenderSequence(k EVMKeeper, ak ante.AccountKeeper) AnteDecEthIncrementSenderSequence { +func NewAnteDecEthIncrementSenderSequence(k *EVMKeeper, ak ante.AccountKeeper) AnteDecEthIncrementSenderSequence { return AnteDecEthIncrementSenderSequence{ evmKeeper: k, accountKeeper: ak, diff --git a/app/evmante/evmante_mempool_fees.go b/app/evmante/evmante_mempool_fees.go index 4f7bdd1a9..16c35d928 100644 --- a/app/evmante/evmante_mempool_fees.go +++ b/app/evmante/evmante_mempool_fees.go @@ -17,12 +17,12 @@ var _ sdk.AnteDecorator = MempoolGasPriceDecorator{} // is rejected. This applies to CheckTx only. // If fee is high enough, then call next AnteHandler type MempoolGasPriceDecorator struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper } // NewMempoolGasPriceDecorator creates a new MinGasPriceDecorator instance used only for // Ethereum transactions. -func NewMempoolGasPriceDecorator(k EVMKeeper) MempoolGasPriceDecorator { +func NewMempoolGasPriceDecorator(k *EVMKeeper) MempoolGasPriceDecorator { return MempoolGasPriceDecorator{ evmKeeper: k, } @@ -40,13 +40,13 @@ func (d MempoolGasPriceDecorator) AnteHandle( minGasPrice := ctx.MinGasPrices().AmountOf(evm.EVMBankDenom) baseFeeMicronibi := d.evmKeeper.BaseFeeMicronibiPerGas(ctx) - baseFeeDec := math.LegacyNewDecFromBigInt(baseFeeMicronibi) + baseFeeMicronibiDec := math.LegacyNewDecFromBigInt(baseFeeMicronibi) // if MinGasPrices is not set, skip the check if minGasPrice.IsZero() { return next(ctx, tx, simulate) - } else if minGasPrice.LT(baseFeeDec) { - minGasPrice = baseFeeDec + } else if minGasPrice.LT(baseFeeMicronibiDec) { + minGasPrice = baseFeeMicronibiDec } for _, msg := range tx.GetMsgs() { diff --git a/app/evmante/evmante_setup_ctx.go b/app/evmante/evmante_setup_ctx.go index f94eae384..9a2e51fa1 100644 --- a/app/evmante/evmante_setup_ctx.go +++ b/app/evmante/evmante_setup_ctx.go @@ -12,10 +12,10 @@ import ( // EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption // by setting the gas meter to infinite type EthSetupContextDecorator struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper } -func NewEthSetUpContextDecorator(k EVMKeeper) EthSetupContextDecorator { +func NewEthSetUpContextDecorator(k *EVMKeeper) EthSetupContextDecorator { return EthSetupContextDecorator{ evmKeeper: k, } diff --git a/app/evmante/evmante_sigverify.go b/app/evmante/evmante_sigverify.go index aff0481eb..31c4a1a7f 100644 --- a/app/evmante/evmante_sigverify.go +++ b/app/evmante/evmante_sigverify.go @@ -14,11 +14,11 @@ import ( // EthSigVerificationDecorator validates an ethereum signatures type EthSigVerificationDecorator struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper } // NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator -func NewEthSigVerificationDecorator(k EVMKeeper) EthSigVerificationDecorator { +func NewEthSigVerificationDecorator(k *EVMKeeper) EthSigVerificationDecorator { return EthSigVerificationDecorator{ evmKeeper: k, } diff --git a/app/evmante/evmante_validate_basic.go b/app/evmante/evmante_validate_basic.go index bc4dd5fa7..b72270a88 100644 --- a/app/evmante/evmante_validate_basic.go +++ b/app/evmante/evmante_validate_basic.go @@ -15,11 +15,11 @@ import ( // EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures type EthValidateBasicDecorator struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper } // NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator -func NewEthValidateBasicDecorator(k EVMKeeper) EthValidateBasicDecorator { +func NewEthValidateBasicDecorator(k *EVMKeeper) EthValidateBasicDecorator { return EthValidateBasicDecorator{ evmKeeper: k, } diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index 7a1feddff..e62af5191 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -14,12 +14,12 @@ import ( // AnteDecVerifyEthAcc validates an account balance checks type AnteDecVerifyEthAcc struct { - evmKeeper EVMKeeper + evmKeeper *EVMKeeper accountKeeper evm.AccountKeeper } // NewAnteDecVerifyEthAcc creates a new EthAccountVerificationDecorator -func NewAnteDecVerifyEthAcc(k EVMKeeper, ak evm.AccountKeeper) AnteDecVerifyEthAcc { +func NewAnteDecVerifyEthAcc(k *EVMKeeper, ak evm.AccountKeeper) AnteDecVerifyEthAcc { return AnteDecVerifyEthAcc{ evmKeeper: k, accountKeeper: ak, diff --git a/app/evmante/interfaces.go b/app/evmante/interfaces.go index 2777ee464..1f433dd21 100644 --- a/app/evmante/interfaces.go +++ b/app/evmante/interfaces.go @@ -2,33 +2,11 @@ package evmante import ( - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/vm" - - "github.com/NibiruChain/nibiru/v2/x/evm" evmkeeper "github.com/NibiruChain/nibiru/v2/x/evm/keeper" - "github.com/NibiruChain/nibiru/v2/x/evm/statedb" + "github.com/cosmos/cosmos-sdk/types/tx" ) -// EVMKeeper defines the expected keeper interface used on the AnteHandler -type EVMKeeper interface { - statedb.Keeper - - NewEVM(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) *vm.EVM - DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error - GetEvmGasBalance(ctx sdk.Context, addr common.Address) *big.Int - ResetTransientGasUsed(ctx sdk.Context) - GetParams(ctx sdk.Context) evm.Params - - EVMState() evmkeeper.EvmState - EthChainID(ctx sdk.Context) *big.Int - BaseFeeMicronibiPerGas(ctx sdk.Context) *big.Int -} +type EVMKeeper = evmkeeper.Keeper type protoTxProvider interface { GetProtoTx() *tx.Tx diff --git a/eth/rpc/backend/blocks.go b/eth/rpc/backend/blocks.go index d688415d0..a64e73e2a 100644 --- a/eth/rpc/backend/blocks.go +++ b/eth/rpc/backend/blocks.go @@ -316,13 +316,13 @@ func (b *Backend) HeaderByNumber(blockNum rpc.BlockNumber) (*gethcore.Header, er b.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height) } - baseFee, err := b.BaseFee(blockRes) + baseFeeWei, err := b.BaseFeeWei(blockRes) if err != nil { // handle the error for pruned node. b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", resBlock.Block.Height, "error", err) } - ethHeader := rpc.EthHeaderFromTendermint(resBlock.Block.Header, bloom, baseFee) + ethHeader := rpc.EthHeaderFromTendermint(resBlock.Block.Header, bloom, baseFeeWei) return ethHeader, nil } @@ -352,7 +352,7 @@ func (b *Backend) RPCBlockFromTendermintBlock( ethRPCTxs := []interface{}{} block := resBlock.Block - baseFee, err := b.BaseFee(blockRes) + baseFeeWei, err := b.BaseFeeWei(blockRes) if err != nil { // handle the error for pruned node. b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", block.Height, "error", err) @@ -374,7 +374,7 @@ func (b *Backend) RPCBlockFromTendermintBlock( gethcommon.BytesToHash(block.Hash()), height, index, - baseFee, + baseFeeWei, b.chainID, ) if err != nil { @@ -434,7 +434,7 @@ func (b *Backend) RPCBlockFromTendermintBlock( formattedBlock := rpc.FormatBlock( block.Header, block.Size(), gasLimit, new(big.Int).SetUint64(gasUsed), - ethRPCTxs, bloom, validatorAddr, baseFee, + ethRPCTxs, bloom, validatorAddr, baseFeeWei, ) return formattedBlock, nil } @@ -471,13 +471,13 @@ func (b *Backend) EthBlockFromTendermintBlock( b.logger.Debug("HeaderByNumber BlockBloom failed", "height", height) } - baseFee, err := b.BaseFee(blockRes) + baseFeeWei, err := b.BaseFeeWei(blockRes) if err != nil { // handle error for pruned node and log b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", height, "error", err) } - ethHeader := rpc.EthHeaderFromTendermint(block.Header, bloom, baseFee) + ethHeader := rpc.EthHeaderFromTendermint(block.Header, bloom, baseFeeWei) msgs := b.EthMsgsFromTendermintBlock(resBlock, blockRes) txs := make([]*gethcore.Transaction, len(msgs)) diff --git a/eth/rpc/backend/chain_info.go b/eth/rpc/backend/chain_info.go index efeededb8..ae1bdd270 100644 --- a/eth/rpc/backend/chain_info.go +++ b/eth/rpc/backend/chain_info.go @@ -33,17 +33,14 @@ func (b *Backend) ChainConfig() *params.ChainConfig { return evm.EthereumConfig(b.chainID) } -// BaseFee returns the base fee tracked by the Fee Market module. +// BaseFeeWei returns the EIP-1559 base fee. // If the base fee is not enabled globally, the query returns nil. -func (b *Backend) BaseFee( +func (b *Backend) BaseFeeWei( blockRes *tmrpctypes.ResultBlockResults, -) (baseFee *big.Int, err error) { - // return BaseFee if feemarket is enabled +) (baseFeeWei *big.Int, err error) { res, err := b.queryClient.BaseFee(rpc.NewContextWithHeight(blockRes.Height), &evm.QueryBaseFeeRequest{}) if err != nil || res.BaseFee == nil { - baseFee = nil - // TODO: feat: dynamic fee handling on events - return baseFee, nil + return nil, nil } return res.BaseFee.BigInt(), nil } diff --git a/eth/rpc/backend/chain_info_test.go b/eth/rpc/backend/chain_info_test.go index 923764888..75b6c06d4 100644 --- a/eth/rpc/backend/chain_info_test.go +++ b/eth/rpc/backend/chain_info_test.go @@ -23,9 +23,9 @@ func (s *BackendSuite) TestChainConfig() { func (s *BackendSuite) TestBaseFee() { resBlock, err := s.backend.TendermintBlockResultByNumber(transferTxBlockNumber.TmHeight()) s.Require().NoError(err) - baseFee, err := s.backend.BaseFee(resBlock) + baseFeeWei, err := s.backend.BaseFeeWei(resBlock) s.Require().NoError(err) - s.Require().Equal(evm.BASE_FEE_MICRONIBI, baseFee) + s.Require().Equal(evm.BASE_FEE_WEI, baseFeeWei) } func (s *BackendSuite) TestCurrentHeader() { diff --git a/eth/rpc/backend/tx_info.go b/eth/rpc/backend/tx_info.go index a8cb127b0..10f6d1bde 100644 --- a/eth/rpc/backend/tx_info.go +++ b/eth/rpc/backend/tx_info.go @@ -70,7 +70,7 @@ func (b *Backend) GetTransactionByHash(txHash gethcommon.Hash) (*rpc.EthTxJsonRP return nil, errors.New("can't find index of ethereum tx") } - baseFee, err := b.BaseFee(blockRes) + baseFeeWei, err := b.BaseFeeWei(blockRes) if err != nil { // handle the error for pruned node. b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", blockRes.Height, "error", err) @@ -83,7 +83,7 @@ func (b *Backend) GetTransactionByHash(txHash gethcommon.Hash) (*rpc.EthTxJsonRP gethcommon.BytesToHash(block.BlockID.Hash.Bytes()), height, index, - baseFee, + baseFeeWei, b.chainID, ) } @@ -248,12 +248,12 @@ func (b *Backend) GetTransactionReceipt(hash gethcommon.Hash) (*TransactionRecei } if dynamicTx, ok := txData.(*evm.DynamicFeeTx); ok { - baseFee, err := b.BaseFee(blockRes) + baseFeeWei, err := b.BaseFeeWei(blockRes) if err != nil { // tolerate the error for pruned node. b.logger.Error("fetch basefee failed, node is pruned?", "height", res.Height, "error", err) } else { - receipt.EffectiveGasPrice = dynamicTx.EffectiveGasPriceWeiPerGas(baseFee) + receipt.EffectiveGasPrice = dynamicTx.EffectiveGasPriceWeiPerGas(baseFeeWei) } } return &receipt, nil @@ -402,7 +402,7 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i msg = ethMsgs[i] } - baseFee, err := b.BaseFee(blockRes) + baseFeeWei, err := b.BaseFeeWei(blockRes) if err != nil { // handle the error for pruned node. b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", block.Block.Height, "error", err) @@ -415,7 +415,7 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i gethcommon.BytesToHash(block.Block.Hash()), height, index, - baseFee, + baseFeeWei, b.chainID, ) } diff --git a/eth/rpc/backend/utils.go b/eth/rpc/backend/utils.go index 0f8506abd..23ce2f410 100644 --- a/eth/rpc/backend/utils.go +++ b/eth/rpc/backend/utils.go @@ -115,7 +115,7 @@ func (b *Backend) retrieveEVMTxFeesFromBlock( targetOneFeeHistory *rpc.OneFeeHistory, ) error { blockHeight := tendermintBlock.Block.Height - blockBaseFee, err := b.BaseFee(tendermintBlockResult) + blockBaseFee, err := b.BaseFeeWei(tendermintBlockResult) if err != nil { return err } diff --git a/eth/rpc/rpc.go b/eth/rpc/rpc.go index ec211a121..de5a97991 100644 --- a/eth/rpc/rpc.go +++ b/eth/rpc/rpc.go @@ -56,7 +56,7 @@ func RawTxToEthTx(clientCtx client.Context, txBz tmtypes.Tx) ([]*evm.MsgEthereum // EthHeaderFromTendermint: Converts a Tendermint block header to an Eth header. func EthHeaderFromTendermint( - header tmtypes.Header, bloom gethcore.Bloom, baseFee *big.Int, + header tmtypes.Header, bloom gethcore.Bloom, baseFeeWei *big.Int, ) *gethcore.Header { txHash := gethcore.EmptyRootHash if len(header.DataHash) == 0 { @@ -80,7 +80,7 @@ func EthHeaderFromTendermint( Extra: []byte{}, MixDigest: gethcommon.Hash{}, Nonce: gethcore.BlockNonce{}, - BaseFee: baseFee, + BaseFee: baseFeeWei, } } @@ -161,11 +161,11 @@ func NewRPCTxFromMsg( msg *evm.MsgEthereumTx, blockHash gethcommon.Hash, blockNumber, index uint64, - baseFee *big.Int, + baseFeeWei *big.Int, chainID *big.Int, ) (*EthTxJsonRPC, error) { tx := msg.AsTransaction() - return NewRPCTxFromEthTx(tx, blockHash, blockNumber, index, baseFee, chainID) + return NewRPCTxFromEthTx(tx, blockHash, blockNumber, index, baseFeeWei, chainID) } // NewRPCTxFromEthTx returns a transaction that will serialize to the RPC diff --git a/eth/rpc/rpcapi/websockets.go b/eth/rpc/rpcapi/websockets.go index a1af04dd4..68fb7eb9e 100644 --- a/eth/rpc/rpcapi/websockets.go +++ b/eth/rpc/rpcapi/websockets.go @@ -393,7 +393,7 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn, subID gethrpc.ID) (pubsu } // TODO: use events - baseFee := big.NewInt(params.InitialBaseFee) + baseFeeWeiPerGas := big.NewInt(params.InitialBaseFee) go func() { headersCh := sub.EventCh @@ -411,7 +411,7 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn, subID gethrpc.ID) (pubsu continue } - header := rpc.EthHeaderFromTendermint(data.Header, gethcore.Bloom{}, baseFee) + header := rpc.EthHeaderFromTendermint(data.Header, gethcore.Bloom{}, baseFeeWeiPerGas) // write to ws conn res := &SubscriptionNotification{ diff --git a/proto/eth/evm/v1/query.proto b/proto/eth/evm/v1/query.proto index f45b12153..a745ae506 100644 --- a/proto/eth/evm/v1/query.proto +++ b/proto/eth/evm/v1/query.proto @@ -293,16 +293,20 @@ message QueryTraceBlockResponse { message QueryBaseFeeRequest {} // QueryBaseFeeResponse returns the EIP1559 base fee. +// See https://github.com/ethereum/EIPs/blob/ba6c342c23164072adb500c3136e3ae6eabff306/EIPS/eip-1559.md. message QueryBaseFeeResponse { - // base_fee is the EIP1559 base fee + // base_fee is the EIP1559 base fee in units of wei. string base_fee = 1 [(gogoproto.customtype) = "cosmossdk.io/math.Int"]; + // base_fee is the EIP1559 base fee in units of micronibi ("unibi"). + string base_fee_unibi = 2 [(gogoproto.customtype) = "cosmossdk.io/math.Int"]; } message QueryFunTokenMappingRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - // either the 0x contract address of the ERC-20 token or the cosmos denom + // Either the hexadecimal-encoded ERC20 contract address or denomination of the + // Bank Coin. string token = 1; } @@ -311,5 +315,5 @@ message QueryFunTokenMappingResponse { option (gogoproto.goproto_getters) = false; // fun_token is a mapping between the Cosmos native coin and the ERC20 contract address - FunToken fun_token = 1; + eth.evm.v1.FunToken fun_token = 1; } diff --git a/x/evm/json_tx_args.go b/x/evm/json_tx_args.go index 603546632..2318250a7 100644 --- a/x/evm/json_tx_args.go +++ b/x/evm/json_tx_args.go @@ -158,7 +158,7 @@ func (args *JsonTxArgs) ToMsgEthTx() *MsgEthereumTx { // ToMessage converts the arguments to the Message type used by the core evm. // This assumes that setTxDefaults has been called. -func (args *JsonTxArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (geth.Message, error) { +func (args *JsonTxArgs) ToMessage(globalGasCap uint64, baseFeeWei *big.Int) (geth.Message, error) { // Reject invalid combinations of pre- and post-1559 fee styles if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return geth.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") @@ -183,7 +183,7 @@ func (args *JsonTxArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (geth.M gasFeeCap *big.Int gasTipCap *big.Int ) - if baseFee == nil { + if baseFeeWei == nil { // If there's no basefee, then it must be a non-1559 execution gasPrice = new(big.Int) if args.GasPrice != nil { @@ -209,7 +209,7 @@ func (args *JsonTxArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (geth.M // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes gasPrice = new(big.Int) if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { - gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap) + gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFeeWei), gasFeeCap) } } } diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 154066d72..c8dfd7fa0 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -144,10 +144,13 @@ func (k Keeper) BaseFee( goCtx context.Context, _ *evm.QueryBaseFeeRequest, ) (*evm.QueryBaseFeeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - baseFee := sdkmath.NewIntFromBigInt(k.BaseFeeMicronibiPerGas(ctx)) + baseFeeMicronibiPerGas := sdkmath.NewIntFromBigInt(k.BaseFeeMicronibiPerGas(ctx)) + baseFeeWei := sdkmath.NewIntFromBigInt( + evm.NativeToWei(baseFeeMicronibiPerGas.BigInt()), + ) return &evm.QueryBaseFeeResponse{ - BaseFee: &baseFee, - // TODO: Show both units + BaseFee: &baseFeeWei, + BaseFeeUnibi: &baseFeeMicronibiPerGas, }, nil } @@ -273,7 +276,7 @@ func (k *Keeper) EthCall( nonce := k.GetAccNonce(ctx, args.GetFrom()) args.Nonce = (*hexutil.Uint64)(&nonce) - msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) + msg, err := args.ToMessage(req.GasCap, cfg.BaseFeeWei) if err != nil { return nil, grpcstatus.Error(grpccodes.InvalidArgument, err.Error()) } @@ -370,7 +373,7 @@ func (k Keeper) EstimateGasForEvmCallType( txConfig := statedb.NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes())) // convert the tx args to an ethereum message - msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) + msg, err := args.ToMessage(req.GasCap, cfg.BaseFeeWei) if err != nil { return nil, grpcstatus.Error(grpccodes.Internal, err.Error()) } @@ -490,9 +493,9 @@ func (k Keeper) TraceTx( } // compute and use base fee of the height that is being traced - baseFee := k.BaseFeeMicronibiPerGas(ctx) - if baseFee != nil { - cfg.BaseFee = baseFee + baseFeeMicronibiPerGas := k.BaseFeeMicronibiPerGas(ctx) + if baseFeeMicronibiPerGas != nil { + cfg.BaseFeeWei = baseFeeMicronibiPerGas } signer := gethcore.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight())) @@ -505,7 +508,7 @@ func (k Keeper) TraceTx( for i, tx := range req.Predecessors { ethTx := tx.AsTransaction() - msg, err := ethTx.AsMessage(signer, cfg.BaseFee) + msg, err := ethTx.AsMessage(signer, cfg.BaseFeeWei) if err != nil { continue } @@ -534,7 +537,7 @@ func (k Keeper) TraceTx( tracerConfig, _ = json.Marshal(req.TraceConfig.TracerConfig) } - msg, err := tx.AsMessage(signer, cfg.BaseFee) + msg, err := tx.AsMessage(signer, cfg.BaseFeeWei) if err != nil { return nil, err } @@ -591,7 +594,7 @@ func (k Keeper) TraceCall( // compute and use base fee of the height that is being traced baseFeeMicronibi := k.BaseFeeMicronibiPerGas(ctx) if baseFeeMicronibi != nil { - cfg.BaseFee = baseFeeMicronibi + cfg.BaseFeeWei = baseFeeMicronibi } txConfig := statedb.NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes())) @@ -678,9 +681,9 @@ func (k Keeper) TraceBlock( } // compute and use base fee of height that is being traced - baseFee := k.BaseFeeMicronibiPerGas(ctx) - if baseFee != nil { - cfg.BaseFee = baseFee + baseFeeMicronibiPerGas := k.BaseFeeMicronibiPerGas(ctx) + if baseFeeMicronibiPerGas != nil { + cfg.BaseFeeWei = baseFeeMicronibiPerGas } var tracerConfig json.RawMessage if req.TraceConfig != nil && req.TraceConfig.TracerConfig != nil { @@ -699,7 +702,7 @@ func (k Keeper) TraceBlock( ethTx := tx.AsTransaction() txConfig.TxHash = ethTx.Hash() txConfig.TxIndex = uint(i) - msg, err := ethTx.AsMessage(signer, cfg.BaseFee) + msg, err := ethTx.AsMessage(signer, cfg.BaseFeeWei) if err != nil { result.Error = err.Error() continue diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 193711d36..46ce456d2 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -608,9 +608,11 @@ func (s *Suite) TestQueryBaseFee() { name: "happy: base fee value", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { req = &evm.QueryBaseFeeRequest{} - zeroFee := math.NewInt(1) + defaultFeeWei := math.NewIntFromBigInt(evm.BASE_FEE_WEI) + defaultFeeUnibi := math.NewIntFromBigInt(evm.BASE_FEE_MICRONIBI) wantResp = &evm.QueryBaseFeeResponse{ - BaseFee: &zeroFee, + BaseFee: &defaultFeeWei, + BaseFeeUnibi: &defaultFeeUnibi, } return req, wantResp }, diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index f0d18c765..08d80383e 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -84,8 +84,8 @@ func NewKeeper( } } -// GetEvmGasBalance: Implements `evm.EVMKeeper` from -// "github.com/NibiruChain/nibiru/v2/app/ante/evm": Load account's balance of gas +// GetEvmGasBalance: Used in the EVM Ante Handler, +// "github.com/NibiruChain/nibiru/v2/app/evmante": Load account's balance of gas // tokens for EVM execution in EVM denom units. func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) (balance *big.Int) { nibiruAddr := sdk.AccAddress(addr.Bytes()) diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index b86e572e7..f926a0b6a 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -56,7 +56,7 @@ func (k *Keeper) ApplyEvmTx( // get the signer according to the chain rules from the config and block height signer := gethcore.MakeSigner(evmConfig.ChainConfig, big.NewInt(ctx.BlockHeight())) - msg, err := tx.AsMessage(signer, evmConfig.BaseFee) + msg, err := tx.AsMessage(signer, evmConfig.BaseFeeWei) if err != nil { return nil, errors.Wrap(err, "failed to return ethereum transaction as core message") } @@ -112,7 +112,7 @@ func (k *Keeper) ApplyEvmTx( if msg.Gas() > evmResp.GasUsed { refundGas = msg.Gas() - evmResp.GasUsed } - weiPerGas := txMsg.EffectiveGasPriceWeiPerGas(evmConfig.BaseFee) + weiPerGas := txMsg.EffectiveGasPriceWeiPerGas(evmConfig.BaseFeeWei) if err = k.RefundGas(ctx, msg.From(), refundGas, weiPerGas); err != nil { return nil, errors.Wrapf(err, "failed to refund leftover gas to sender %s", msg.From()) } @@ -162,12 +162,12 @@ func (k *Keeper) NewEVM( CanTransfer: core.CanTransfer, Transfer: core.Transfer, GetHash: k.GetHashFn(ctx), - Coinbase: evmConfig.CoinBase, + Coinbase: evmConfig.BlockCoinbase, GasLimit: eth.BlockGasLimit(ctx), BlockNumber: big.NewInt(ctx.BlockHeight()), Time: big.NewInt(ctx.BlockHeader().Time.Unix()), Difficulty: big.NewInt(0), // unused. Only required in PoW context - BaseFee: evmConfig.BaseFee, + BaseFee: evmConfig.BaseFeeWei, Random: nil, // not supported } diff --git a/x/evm/keeper/vm_config.go b/x/evm/keeper/vm_config.go index 10f7c14d7..59c380e08 100644 --- a/x/evm/keeper/vm_config.go +++ b/x/evm/keeper/vm_config.go @@ -27,12 +27,12 @@ func (k *Keeper) GetEVMConfig( return nil, errors.Wrap(err, "failed to obtain coinbase address") } - baseFee := k.BaseFeeMicronibiPerGas(ctx) + baseFeeMicronibiPerGas := k.BaseFeeMicronibiPerGas(ctx) return &statedb.EVMConfig{ - Params: params, - ChainConfig: ethCfg, - CoinBase: coinbase, - BaseFee: baseFee, + Params: params, + ChainConfig: ethCfg, + BlockCoinbase: coinbase, + BaseFeeWei: baseFeeMicronibiPerGas, }, nil } @@ -68,6 +68,10 @@ func (k Keeper) VMConfig( } // GetCoinbaseAddress returns the block proposer's validator operator address. +// In Ethereum, the coinbase (or "benficiary") is the address that proposed the +// current block. It corresponds to the [COINBASE op code]. +// +// [COINBASE op code]: https://ethereum.org/en/developers/docs/evm/opcodes/ func (k Keeper) GetCoinbaseAddress(ctx sdk.Context, proposerAddress sdk.ConsAddress) (common.Address, error) { validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, ParseProposerAddr(ctx, proposerAddress)) if !found { diff --git a/x/evm/query.pb.go b/x/evm/query.pb.go index 83b582c56..a710bd10d 100644 --- a/x/evm/query.pb.go +++ b/x/evm/query.pb.go @@ -1201,6 +1201,8 @@ var xxx_messageInfo_QueryBaseFeeRequest proto.InternalMessageInfo type QueryBaseFeeResponse struct { // base_fee is the EIP1559 base fee BaseFee *cosmossdk_io_math.Int `protobuf:"bytes,1,opt,name=base_fee,json=baseFee,proto3,customtype=cosmossdk.io/math.Int" json:"base_fee,omitempty"` + // base_fee is the EIP1559 base fee in units of micronibi ("unibi"). + BaseFeeUnibi *cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=base_fee_unibi,json=baseFeeUnibi,proto3,customtype=cosmossdk.io/math.Int" json:"base_fee_unibi,omitempty"` } func (m *QueryBaseFeeResponse) Reset() { *m = QueryBaseFeeResponse{} } @@ -1342,105 +1344,107 @@ func init() { func init() { proto.RegisterFile("eth/evm/v1/query.proto", fileDescriptor_ffa36cdc5add14ed) } var fileDescriptor_ffa36cdc5add14ed = []byte{ - // 1568 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0x8f, 0x63, 0x27, 0x76, 0x9e, 0xd3, 0x26, 0x4c, 0xd3, 0x26, 0x71, 0x12, 0x3b, 0xd9, 0x40, - 0x92, 0x96, 0x76, 0x97, 0xb8, 0x08, 0x44, 0x45, 0x25, 0xea, 0x28, 0x0d, 0xa5, 0x7f, 0xd4, 0x9a, - 0x08, 0x24, 0x10, 0xb2, 0xc6, 0xf6, 0x64, 0xbd, 0x8a, 0xbd, 0xe3, 0x7a, 0xc6, 0xae, 0x43, 0xc9, - 0x85, 0x5e, 0x90, 0x10, 0x52, 0x25, 0xbe, 0x40, 0x4f, 0x7c, 0x04, 0xf8, 0x0a, 0xbd, 0x51, 0x89, - 0x0b, 0xe2, 0x50, 0x50, 0xcb, 0x81, 0x33, 0x47, 0x4e, 0x68, 0xfe, 0xd9, 0x6b, 0x7b, 0x9d, 0x50, - 0x15, 0x6e, 0x9c, 0x76, 0xe6, 0xcd, 0x7b, 0xbf, 0xf7, 0x9b, 0x37, 0x6f, 0xdf, 0x7b, 0x70, 0x86, - 0xf0, 0x8a, 0x43, 0x5a, 0x35, 0xa7, 0xb5, 0xe9, 0xdc, 0x6d, 0x92, 0xc6, 0x81, 0x5d, 0x6f, 0x50, - 0x4e, 0x11, 0x10, 0x5e, 0xb1, 0x49, 0xab, 0x66, 0xb7, 0x36, 0x53, 0xe7, 0x4a, 0x94, 0xd5, 0x28, - 0x73, 0x8a, 0x98, 0x11, 0xa5, 0xe4, 0xb4, 0x36, 0x8b, 0x84, 0xe3, 0x4d, 0xa7, 0x8e, 0x5d, 0xcf, - 0xc7, 0xdc, 0xa3, 0xbe, 0xb2, 0x4b, 0xcd, 0x04, 0xf0, 0x84, 0xb9, 0x92, 0x9e, 0x0a, 0x48, 0x79, - 0xdb, 0xa8, 0xba, 0xd4, 0xa5, 0x72, 0xe9, 0x88, 0x95, 0x96, 0x2e, 0xba, 0x94, 0xba, 0x55, 0xe2, - 0xe0, 0xba, 0xe7, 0x60, 0xdf, 0xa7, 0x5c, 0xa2, 0x33, 0x7d, 0x9a, 0xd1, 0xa7, 0x72, 0x57, 0x6c, - 0xee, 0x39, 0xdc, 0xab, 0x11, 0xc6, 0x71, 0xad, 0xae, 0x14, 0xac, 0x77, 0xe1, 0xcc, 0x1d, 0xc1, - 0x70, 0x9b, 0x57, 0xae, 0x94, 0x4a, 0xb4, 0xe9, 0xf3, 0x3c, 0xb9, 0xdb, 0x24, 0x8c, 0xa3, 0x39, - 0x88, 0xe3, 0x72, 0xb9, 0x41, 0x18, 0x9b, 0x8b, 0x2c, 0x47, 0x36, 0x26, 0xf2, 0x66, 0x7b, 0x29, - 0xf1, 0xd5, 0xa3, 0xcc, 0xc8, 0x1f, 0x8f, 0x32, 0x23, 0xd6, 0x8f, 0x11, 0x98, 0x1d, 0x30, 0x67, - 0x75, 0xea, 0x33, 0x22, 0xec, 0x8b, 0xb8, 0x8a, 0xfd, 0x12, 0x31, 0xf6, 0x7a, 0x8b, 0x32, 0x90, - 0xd4, 0xcb, 0xc2, 0x3d, 0xe2, 0xcd, 0x8d, 0xca, 0x53, 0xd0, 0xa2, 0x8f, 0x89, 0x87, 0x16, 0x60, - 0xa2, 0x44, 0xcb, 0xa4, 0x50, 0xc1, 0xac, 0x32, 0x17, 0x95, 0xc7, 0x09, 0x21, 0x78, 0x1f, 0xb3, - 0x0a, 0x9a, 0x81, 0x31, 0x9f, 0x0a, 0xd4, 0xd8, 0x72, 0x64, 0x23, 0x96, 0x57, 0x1b, 0x81, 0x49, - 0x78, 0xa5, 0x60, 0x18, 0x8f, 0x29, 0x4c, 0xc2, 0x2b, 0x57, 0x94, 0x04, 0xbd, 0x06, 0x27, 0x8b, - 0xa4, 0x54, 0xb9, 0x98, 0xed, 0xe8, 0x8c, 0x4b, 0x9d, 0x13, 0x4a, 0xaa, 0xd5, 0xac, 0xeb, 0xb0, - 0x28, 0x2f, 0xf4, 0x11, 0xae, 0x7a, 0x65, 0xcc, 0x69, 0xa3, 0x2f, 0x2a, 0x2b, 0x30, 0x59, 0xa2, - 0x3e, 0x2b, 0xf4, 0x86, 0x26, 0x29, 0x64, 0x57, 0x06, 0xc2, 0xf3, 0x75, 0x04, 0x96, 0x86, 0xa0, - 0xe9, 0x20, 0xad, 0xc3, 0x14, 0x56, 0xa2, 0x3e, 0xc4, 0x93, 0x5a, 0x6c, 0xe8, 0xa7, 0x20, 0xc1, - 0x04, 0x05, 0x71, 0xf1, 0x51, 0x79, 0xf1, 0xce, 0x5e, 0x5c, 0xcd, 0x80, 0xf8, 0xcd, 0x5a, 0x91, - 0x34, 0x64, 0xcc, 0x62, 0xf9, 0x13, 0x5a, 0x7a, 0x4b, 0x0a, 0xad, 0x77, 0xe0, 0x94, 0x24, 0x93, - 0x53, 0x81, 0x7e, 0x91, 0x77, 0xbe, 0x03, 0x33, 0xbd, 0xa6, 0x2f, 0xfd, 0xc6, 0xd6, 0x75, 0xcd, - 0xe6, 0x43, 0x4e, 0x1b, 0xd8, 0x3d, 0x9e, 0x0d, 0x9a, 0x86, 0xe8, 0x3e, 0x39, 0xd0, 0x48, 0x62, - 0x19, 0xe0, 0x77, 0x5e, 0xf3, 0xeb, 0x80, 0x69, 0x7e, 0x33, 0x30, 0xd6, 0xc2, 0xd5, 0xa6, 0x61, - 0xa7, 0x36, 0xd6, 0x5b, 0x30, 0x2d, 0xb5, 0xb7, 0x68, 0xf9, 0x85, 0xa2, 0xb0, 0x0e, 0xaf, 0x04, - 0xec, 0xb4, 0x0b, 0x04, 0x31, 0x91, 0x9a, 0xd2, 0x6a, 0x32, 0x2f, 0xd7, 0xd6, 0xe7, 0x80, 0xa4, - 0xe2, 0x6e, 0xfb, 0x06, 0x75, 0x99, 0x71, 0x81, 0x20, 0x26, 0x13, 0x5a, 0xe1, 0xcb, 0x35, 0xba, - 0x0a, 0xd0, 0x2d, 0x09, 0xf2, 0x6e, 0xc9, 0xec, 0x9a, 0xad, 0xea, 0x87, 0x2d, 0xea, 0x87, 0xad, - 0x8a, 0x8c, 0xae, 0x1f, 0xf6, 0xed, 0x6e, 0xa8, 0xf2, 0x01, 0xcb, 0x00, 0xc9, 0x07, 0x11, 0x1d, - 0x58, 0xe3, 0x5c, 0xf3, 0x5c, 0x85, 0x58, 0x95, 0xba, 0xe2, 0x76, 0xd1, 0x8d, 0x64, 0x76, 0xca, - 0xee, 0xd6, 0x2b, 0xfb, 0x06, 0x75, 0xf3, 0xf2, 0x10, 0xed, 0x84, 0xd0, 0x59, 0x3f, 0x96, 0x8e, - 0xf2, 0x10, 0xe4, 0x63, 0xcd, 0xe8, 0x08, 0xdc, 0xc6, 0x0d, 0x5c, 0x33, 0x11, 0xb0, 0x76, 0x34, - 0x35, 0x23, 0xd5, 0xd4, 0xde, 0x80, 0xf1, 0xba, 0x94, 0xc8, 0xd0, 0x24, 0xb3, 0x28, 0x48, 0x4e, - 0xe9, 0xe6, 0x62, 0x8f, 0x9f, 0x66, 0x46, 0xf2, 0x5a, 0xcf, 0xfa, 0x21, 0x02, 0x27, 0xb7, 0x79, - 0x65, 0x0b, 0x57, 0xab, 0x81, 0xe8, 0xe2, 0x86, 0xcb, 0xcc, 0x3b, 0x88, 0x35, 0x9a, 0x85, 0xb8, - 0x8b, 0x59, 0xa1, 0x84, 0xeb, 0xfa, 0x9f, 0x19, 0x77, 0x31, 0xdb, 0xc2, 0x75, 0xf4, 0x19, 0x4c, - 0xd7, 0x1b, 0xb4, 0x4e, 0x19, 0x69, 0x74, 0xfe, 0x3b, 0xf1, 0xcf, 0x4c, 0xe6, 0xb2, 0x7f, 0x3d, - 0xcd, 0xd8, 0xae, 0xc7, 0x2b, 0xcd, 0xa2, 0x5d, 0xa2, 0x35, 0x47, 0x97, 0x72, 0xf5, 0xb9, 0xc0, - 0xca, 0xfb, 0x0e, 0x3f, 0xa8, 0x13, 0x66, 0x6f, 0x75, 0x7f, 0xf8, 0xfc, 0x94, 0xc1, 0x32, 0x3f, - 0xeb, 0x3c, 0x24, 0x4a, 0x15, 0xec, 0xf9, 0x05, 0xaf, 0x2c, 0xab, 0x54, 0x34, 0x1f, 0x97, 0xfb, - 0x6b, 0x65, 0x6b, 0x1d, 0x4e, 0x6d, 0x33, 0xee, 0xd5, 0x30, 0x27, 0x3b, 0xb8, 0x1b, 0x82, 0x69, - 0x88, 0xba, 0x58, 0x91, 0x8f, 0xe5, 0xc5, 0xd2, 0xfa, 0x33, 0x6a, 0xde, 0xb1, 0x81, 0x4b, 0x64, - 0xb7, 0x6d, 0xee, 0xf9, 0x3a, 0x44, 0x6b, 0xcc, 0xd5, 0x91, 0x9a, 0x0f, 0x46, 0xea, 0x26, 0x73, - 0xb7, 0x79, 0x85, 0x34, 0x48, 0xb3, 0xb6, 0xdb, 0xce, 0x0b, 0x2d, 0x74, 0x09, 0x26, 0xb9, 0x30, - 0x2f, 0x94, 0xa8, 0xbf, 0xe7, 0xb9, 0xf2, 0x8e, 0xc9, 0xec, 0x6c, 0xd0, 0x4a, 0xc2, 0x6f, 0xc9, - 0xe3, 0x7c, 0x92, 0x77, 0x37, 0xe8, 0x32, 0x4c, 0xd6, 0x1b, 0xa4, 0x4c, 0x4a, 0x84, 0x31, 0xda, - 0x60, 0x73, 0x31, 0x99, 0x38, 0x47, 0x78, 0xec, 0x51, 0x17, 0x85, 0xb2, 0x58, 0xa5, 0xa5, 0x7d, - 0x53, 0x92, 0xc6, 0x64, 0x1c, 0x92, 0x52, 0xa6, 0x0a, 0x12, 0x5a, 0x02, 0x50, 0x2a, 0xf2, 0xb7, - 0x50, 0xe5, 0x78, 0x42, 0x4a, 0x64, 0xa1, 0xdf, 0x32, 0xc7, 0xa2, 0x67, 0xcd, 0xc5, 0x25, 0xf5, - 0x94, 0xad, 0x1a, 0x9a, 0x6d, 0x1a, 0x9a, 0xbd, 0x6b, 0x1a, 0x5a, 0x2e, 0x21, 0x52, 0xe4, 0xe1, - 0xaf, 0x99, 0x88, 0x06, 0x11, 0x27, 0xa1, 0x2f, 0x9d, 0xf8, 0x6f, 0x5e, 0x7a, 0xa2, 0xe7, 0xa5, - 0x91, 0x05, 0x27, 0x14, 0xfd, 0x1a, 0x6e, 0x17, 0xc4, 0xe3, 0x42, 0x20, 0x02, 0x37, 0x71, 0x7b, - 0x07, 0xb3, 0x0f, 0x62, 0x89, 0xd1, 0xe9, 0x68, 0x3e, 0xc1, 0xdb, 0x05, 0xcf, 0x2f, 0x93, 0xb6, - 0x75, 0x4e, 0xd7, 0xb1, 0xce, 0x9b, 0x77, 0x8b, 0x4c, 0x19, 0x73, 0x6c, 0x92, 0x5b, 0xac, 0xad, - 0xef, 0xa2, 0xba, 0x75, 0x4b, 0xe5, 0x9c, 0x40, 0x0d, 0xe4, 0x08, 0x6f, 0x9b, 0x5f, 0xfd, 0xa8, - 0x1c, 0xe1, 0x6d, 0xf6, 0x52, 0x39, 0xf2, 0xff, 0x23, 0x1f, 0xff, 0xc8, 0xd6, 0x05, 0x3d, 0x23, - 0x05, 0xdf, 0xe9, 0x88, 0x77, 0x3d, 0xdd, 0x69, 0xd3, 0x8c, 0x5c, 0x25, 0xa6, 0xda, 0x5b, 0x37, - 0x3a, 0x2d, 0x58, 0x8b, 0x35, 0xc4, 0x9b, 0x90, 0x10, 0x85, 0xb9, 0xb0, 0x47, 0x74, 0x97, 0xcb, - 0xcd, 0xff, 0xf2, 0x34, 0x73, 0x5a, 0xdd, 0x90, 0x95, 0xf7, 0x6d, 0x8f, 0x3a, 0x35, 0xcc, 0x2b, - 0xf6, 0x35, 0x9f, 0x8b, 0xf6, 0x2c, 0xad, 0xad, 0xcb, 0xb0, 0x20, 0xd1, 0xae, 0x36, 0xfd, 0x5d, - 0xba, 0x4f, 0xfc, 0x9b, 0xb8, 0x5e, 0xf7, 0x7c, 0xd7, 0x24, 0xd0, 0x0c, 0x8c, 0x71, 0x21, 0x36, - 0x7d, 0x53, 0x6e, 0x02, 0x4d, 0xe6, 0x53, 0x3d, 0x25, 0x0d, 0x98, 0x6b, 0x52, 0x9b, 0x30, 0xb1, - 0xd7, 0xf4, 0x0b, 0x5d, 0x8c, 0x64, 0x76, 0x26, 0x98, 0x50, 0xc6, 0x2e, 0x9f, 0xd8, 0xd3, 0xab, - 0x2e, 0x78, 0xf6, 0xfb, 0x49, 0x18, 0x93, 0xe8, 0xe8, 0x41, 0x04, 0xa0, 0x3b, 0x59, 0x22, 0x2b, - 0x08, 0x11, 0x3e, 0xb5, 0xa6, 0x56, 0x8f, 0xd4, 0x51, 0xf4, 0xac, 0xf3, 0x5f, 0xfe, 0xf4, 0xfb, - 0xb7, 0xa3, 0x6b, 0xe8, 0x55, 0xc7, 0xf7, 0x8a, 0x5e, 0xa3, 0xd9, 0x19, 0xc0, 0xc5, 0x04, 0xa9, - 0x74, 0x9d, 0xfb, 0x3a, 0x91, 0x0e, 0xd1, 0xa3, 0x08, 0x4c, 0xf7, 0x0f, 0x70, 0x68, 0x63, 0xc0, - 0xcf, 0x90, 0x89, 0x31, 0x75, 0xf6, 0x1f, 0x68, 0x6a, 0x5e, 0x6f, 0x4b, 0x5e, 0x9b, 0xc8, 0xe9, - 0xe3, 0xd5, 0x32, 0x06, 0x5d, 0x76, 0xc1, 0x21, 0xf4, 0x10, 0xdd, 0x83, 0x78, 0xce, 0x0c, 0x5e, - 0x03, 0xee, 0x7a, 0xe7, 0xbd, 0xd4, 0xf2, 0x70, 0x05, 0x4d, 0xe3, 0xac, 0xa4, 0xb1, 0x8a, 0x56, - 0xfa, 0x68, 0xe8, 0xe9, 0x8d, 0x05, 0x62, 0xf3, 0x05, 0xc4, 0xf5, 0xcc, 0x15, 0xe2, 0xb8, 0x77, - 0xb4, 0x0b, 0x71, 0xdc, 0x37, 0xae, 0x59, 0xb6, 0x74, 0xbc, 0x81, 0xd6, 0xfa, 0x1c, 0x33, 0xa5, - 0xd7, 0xf5, 0xeb, 0xdc, 0xdf, 0x27, 0x07, 0x87, 0x68, 0x1f, 0x62, 0x62, 0x16, 0x43, 0x8b, 0x03, - 0xc8, 0x81, 0xd1, 0x2e, 0xb5, 0x34, 0xe4, 0x54, 0x3b, 0x5d, 0x93, 0x4e, 0x97, 0x51, 0xba, 0xcf, - 0xa9, 0x98, 0xe4, 0x82, 0x57, 0xad, 0xc0, 0xb8, 0x9a, 0x45, 0x50, 0x7a, 0x00, 0xb0, 0x67, 0xcc, - 0x49, 0x65, 0x86, 0x9e, 0x6b, 0x97, 0x4b, 0xd2, 0xe5, 0x2c, 0x3a, 0xdd, 0xe7, 0x52, 0x4d, 0x37, - 0xc8, 0x83, 0xb8, 0x1e, 0x6e, 0x50, 0x2a, 0x08, 0xd5, 0x3b, 0xf1, 0xa4, 0x56, 0x86, 0x17, 0x76, - 0xe3, 0x28, 0x23, 0x1d, 0xcd, 0xa3, 0xd9, 0x90, 0x44, 0x2f, 0x09, 0x7c, 0x0a, 0xc9, 0xc0, 0x38, - 0x72, 0xa4, 0xbb, 0x9e, 0x5b, 0x85, 0xcc, 0x30, 0xd6, 0xaa, 0x74, 0xb6, 0x84, 0x16, 0xfa, 0x9d, - 0x69, 0x5d, 0x51, 0x1f, 0x51, 0x0d, 0xe2, 0xba, 0xb9, 0x85, 0x24, 0x4c, 0xef, 0xa8, 0x13, 0x92, - 0x30, 0x7d, 0x7d, 0x71, 0xe8, 0xfd, 0x54, 0x43, 0xe3, 0x6d, 0x74, 0x00, 0xd0, 0x2d, 0xbb, 0x21, - 0x05, 0x64, 0xa0, 0x77, 0x86, 0x14, 0x90, 0xc1, 0xba, 0x6d, 0x59, 0xd2, 0xef, 0x22, 0x4a, 0x85, - 0xfa, 0x95, 0xc5, 0x1f, 0xdd, 0x85, 0x09, 0xd5, 0x37, 0x45, 0x9c, 0xff, 0x85, 0xbb, 0xae, 0x48, - 0x9f, 0x0b, 0x68, 0x3e, 0xd4, 0xa7, 0x7c, 0xcd, 0x9a, 0x28, 0x03, 0xb2, 0xc0, 0x87, 0x96, 0x81, - 0x60, 0x3f, 0x09, 0x2d, 0x03, 0x3d, 0x9d, 0x65, 0x68, 0x70, 0x4d, 0xbb, 0x41, 0xdf, 0x44, 0x60, - 0xaa, 0xaf, 0x03, 0xa0, 0xf5, 0x01, 0xd8, 0xf0, 0x16, 0x93, 0xda, 0x38, 0x5e, 0x51, 0xf3, 0x58, - 0x97, 0x3c, 0x56, 0x50, 0xa6, 0x8f, 0xc7, 0x5e, 0xd3, 0x97, 0x0d, 0xc6, 0xb9, 0x2f, 0x3f, 0x87, - 0xb9, 0xf7, 0x1e, 0x3f, 0x4b, 0x47, 0x9e, 0x3c, 0x4b, 0x47, 0x7e, 0x7b, 0x96, 0x8e, 0x3c, 0x7c, - 0x9e, 0x1e, 0x79, 0xf2, 0x3c, 0x3d, 0xf2, 0xf3, 0xf3, 0xf4, 0xc8, 0x27, 0x6b, 0x81, 0x11, 0xe0, - 0x96, 0x04, 0xd9, 0x12, 0x0d, 0xdc, 0x00, 0xb6, 0xb2, 0x4e, 0x5b, 0xa0, 0x16, 0xc7, 0xe5, 0xc4, - 0x71, 0xf1, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x51, 0x28, 0x9e, 0xd1, 0xe6, 0x11, 0x00, 0x00, + // 1592 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0x5b, 0xc5, + 0x16, 0x8f, 0x63, 0x27, 0x76, 0x8e, 0xd3, 0x24, 0x6f, 0x9a, 0x36, 0x89, 0x93, 0xd8, 0xc9, 0xcd, + 0x7b, 0x49, 0xda, 0xd7, 0xde, 0xfb, 0xe2, 0x3e, 0xbd, 0xa7, 0x57, 0xbd, 0x0a, 0xea, 0x28, 0x0d, + 0xa5, 0x7f, 0xd4, 0x9a, 0x00, 0x12, 0x08, 0x59, 0x63, 0x7b, 0x72, 0x7d, 0x15, 0xfb, 0x8e, 0xeb, + 0x19, 0xbb, 0x0e, 0x25, 0x1b, 0xba, 0x41, 0x42, 0x95, 0x2a, 0xf1, 0x05, 0xba, 0xe2, 0x23, 0xc0, + 0x57, 0xe8, 0x8e, 0x4a, 0x6c, 0x10, 0x8b, 0x82, 0x5a, 0x16, 0xac, 0x59, 0xb2, 0x42, 0xf3, 0xcf, + 0xbe, 0xb6, 0xaf, 0x13, 0xaa, 0xc2, 0x8e, 0xd5, 0x9d, 0x39, 0x73, 0xfe, 0xfc, 0xe6, 0xcc, 0xb9, + 0xe7, 0xfc, 0xe0, 0x2c, 0xe1, 0x15, 0x87, 0xb4, 0x6a, 0x4e, 0x6b, 0xcb, 0xb9, 0xd7, 0x24, 0x8d, + 0x43, 0xbb, 0xde, 0xa0, 0x9c, 0x22, 0x20, 0xbc, 0x62, 0x93, 0x56, 0xcd, 0x6e, 0x6d, 0xa5, 0xce, + 0x97, 0x28, 0xab, 0x51, 0xe6, 0x14, 0x31, 0x23, 0x4a, 0xc9, 0x69, 0x6d, 0x15, 0x09, 0xc7, 0x5b, + 0x4e, 0x1d, 0xbb, 0x9e, 0x8f, 0xb9, 0x47, 0x7d, 0x65, 0x97, 0x9a, 0x0d, 0xf8, 0x13, 0xe6, 0x4a, + 0x7a, 0x3a, 0x20, 0xe5, 0x6d, 0xa3, 0xea, 0x52, 0x97, 0xca, 0xa5, 0x23, 0x56, 0x5a, 0xba, 0xe4, + 0x52, 0xea, 0x56, 0x89, 0x83, 0xeb, 0x9e, 0x83, 0x7d, 0x9f, 0x72, 0xe9, 0x9d, 0xe9, 0xd3, 0x8c, + 0x3e, 0x95, 0xbb, 0x62, 0x73, 0xdf, 0xe1, 0x5e, 0x8d, 0x30, 0x8e, 0x6b, 0x75, 0xa5, 0x60, 0xfd, + 0x1f, 0xce, 0xde, 0x15, 0x08, 0x77, 0x78, 0xe5, 0x6a, 0xa9, 0x44, 0x9b, 0x3e, 0xcf, 0x93, 0x7b, + 0x4d, 0xc2, 0x38, 0x9a, 0x87, 0x38, 0x2e, 0x97, 0x1b, 0x84, 0xb1, 0xf9, 0xc8, 0x4a, 0x64, 0x73, + 0x22, 0x6f, 0xb6, 0x97, 0x13, 0x9f, 0x3d, 0xc9, 0x8c, 0xfc, 0xfc, 0x24, 0x33, 0x62, 0x7d, 0x13, + 0x81, 0xb9, 0x01, 0x73, 0x56, 0xa7, 0x3e, 0x23, 0xc2, 0xbe, 0x88, 0xab, 0xd8, 0x2f, 0x11, 0x63, + 0xaf, 0xb7, 0x28, 0x03, 0x49, 0xbd, 0x2c, 0xdc, 0x27, 0xde, 0xfc, 0xa8, 0x3c, 0x05, 0x2d, 0x7a, + 0x9f, 0x78, 0x68, 0x11, 0x26, 0x4a, 0xb4, 0x4c, 0x0a, 0x15, 0xcc, 0x2a, 0xf3, 0x51, 0x79, 0x9c, + 0x10, 0x82, 0xb7, 0x30, 0xab, 0xa0, 0x59, 0x18, 0xf3, 0xa9, 0xf0, 0x1a, 0x5b, 0x89, 0x6c, 0xc6, + 0xf2, 0x6a, 0x23, 0x7c, 0x12, 0x5e, 0x29, 0x18, 0xc4, 0x63, 0xca, 0x27, 0xe1, 0x95, 0xab, 0x4a, + 0x82, 0xfe, 0x01, 0x53, 0x45, 0x52, 0xaa, 0x5c, 0xca, 0x76, 0x74, 0xc6, 0xa5, 0xce, 0x29, 0x25, + 0xd5, 0x6a, 0xd6, 0x0d, 0x58, 0x92, 0x17, 0x7a, 0x0f, 0x57, 0xbd, 0x32, 0xe6, 0xb4, 0xd1, 0x97, + 0x95, 0x55, 0x98, 0x2c, 0x51, 0x9f, 0x15, 0x7a, 0x53, 0x93, 0x14, 0xb2, 0xab, 0x03, 0xe9, 0xf9, + 0x3c, 0x02, 0xcb, 0x43, 0xbc, 0xe9, 0x24, 0x6d, 0xc0, 0x34, 0x56, 0xa2, 0x3e, 0x8f, 0x53, 0x5a, + 0x6c, 0xe0, 0xa7, 0x20, 0xc1, 0x04, 0x04, 0x71, 0xf1, 0x51, 0x79, 0xf1, 0xce, 0x5e, 0x5c, 0xcd, + 0x38, 0xf1, 0x9b, 0xb5, 0x22, 0x69, 0xc8, 0x9c, 0xc5, 0xf2, 0xa7, 0xb4, 0xf4, 0xb6, 0x14, 0x5a, + 0xff, 0x83, 0xd3, 0x12, 0x4c, 0x4e, 0x25, 0xfa, 0x55, 0xde, 0xf9, 0x2e, 0xcc, 0xf6, 0x9a, 0xbe, + 0xf6, 0x1b, 0x5b, 0x37, 0x34, 0x9a, 0x77, 0x38, 0x6d, 0x60, 0xf7, 0x64, 0x34, 0x68, 0x06, 0xa2, + 0x07, 0xe4, 0x50, 0x7b, 0x12, 0xcb, 0x00, 0xbe, 0x0b, 0x1a, 0x5f, 0xc7, 0x99, 0xc6, 0x37, 0x0b, + 0x63, 0x2d, 0x5c, 0x6d, 0x1a, 0x74, 0x6a, 0x63, 0xfd, 0x07, 0x66, 0xa4, 0xf6, 0x36, 0x2d, 0xbf, + 0x52, 0x16, 0x36, 0xe0, 0x6f, 0x01, 0x3b, 0x1d, 0x02, 0x41, 0x4c, 0x94, 0xa6, 0xb4, 0x9a, 0xcc, + 0xcb, 0xb5, 0xf5, 0x31, 0x20, 0xa9, 0xb8, 0xd7, 0xbe, 0x49, 0x5d, 0x66, 0x42, 0x20, 0x88, 0xc9, + 0x82, 0x56, 0xfe, 0xe5, 0x1a, 0x5d, 0x03, 0xe8, 0xb6, 0x04, 0x79, 0xb7, 0x64, 0x76, 0xdd, 0x56, + 0xfd, 0xc3, 0x16, 0xfd, 0xc3, 0x56, 0x4d, 0x46, 0xf7, 0x0f, 0xfb, 0x4e, 0x37, 0x55, 0xf9, 0x80, + 0x65, 0x00, 0xe4, 0xc3, 0x88, 0x4e, 0xac, 0x09, 0xae, 0x71, 0xae, 0x41, 0xac, 0x4a, 0x5d, 0x71, + 0xbb, 0xe8, 0x66, 0x32, 0x3b, 0x6d, 0x77, 0xfb, 0x95, 0x7d, 0x93, 0xba, 0x79, 0x79, 0x88, 0x76, + 0x43, 0xe0, 0x6c, 0x9c, 0x08, 0x47, 0x45, 0x08, 0xe2, 0xb1, 0x66, 0x75, 0x06, 0xee, 0xe0, 0x06, + 0xae, 0x99, 0x0c, 0x58, 0xbb, 0x1a, 0x9a, 0x91, 0x6a, 0x68, 0xff, 0x82, 0xf1, 0xba, 0x94, 0xc8, + 0xd4, 0x24, 0xb3, 0x28, 0x08, 0x4e, 0xe9, 0xe6, 0x62, 0x4f, 0x9f, 0x67, 0x46, 0xf2, 0x5a, 0xcf, + 0xfa, 0x3a, 0x02, 0x53, 0x3b, 0xbc, 0xb2, 0x8d, 0xab, 0xd5, 0x40, 0x76, 0x71, 0xc3, 0x65, 0xe6, + 0x1d, 0xc4, 0x1a, 0xcd, 0x41, 0xdc, 0xc5, 0xac, 0x50, 0xc2, 0x75, 0xfd, 0xcf, 0x8c, 0xbb, 0x98, + 0x6d, 0xe3, 0x3a, 0xfa, 0x08, 0x66, 0xea, 0x0d, 0x5a, 0xa7, 0x8c, 0x34, 0x3a, 0xff, 0x9d, 0xf8, + 0x67, 0x26, 0x73, 0xd9, 0x5f, 0x9f, 0x67, 0x6c, 0xd7, 0xe3, 0x95, 0x66, 0xd1, 0x2e, 0xd1, 0x9a, + 0xa3, 0x5b, 0xb9, 0xfa, 0x5c, 0x64, 0xe5, 0x03, 0x87, 0x1f, 0xd6, 0x09, 0xb3, 0xb7, 0xbb, 0x3f, + 0x7c, 0x7e, 0xda, 0xf8, 0x32, 0x3f, 0xeb, 0x02, 0x24, 0x4a, 0x15, 0xec, 0xf9, 0x05, 0xaf, 0x2c, + 0xbb, 0x54, 0x34, 0x1f, 0x97, 0xfb, 0xeb, 0x65, 0x6b, 0x03, 0x4e, 0xef, 0x30, 0xee, 0xd5, 0x30, + 0x27, 0xbb, 0xb8, 0x9b, 0x82, 0x19, 0x88, 0xba, 0x58, 0x81, 0x8f, 0xe5, 0xc5, 0xd2, 0xfa, 0x25, + 0x6a, 0xde, 0xb1, 0x81, 0x4b, 0x64, 0xaf, 0x6d, 0xee, 0xf9, 0x4f, 0x88, 0xd6, 0x98, 0xab, 0x33, + 0xb5, 0x10, 0xcc, 0xd4, 0x2d, 0xe6, 0xee, 0xf0, 0x0a, 0x69, 0x90, 0x66, 0x6d, 0xaf, 0x9d, 0x17, + 0x5a, 0xe8, 0x32, 0x4c, 0x72, 0x61, 0x5e, 0x28, 0x51, 0x7f, 0xdf, 0x73, 0xe5, 0x1d, 0x93, 0xd9, + 0xb9, 0xa0, 0x95, 0x74, 0xbf, 0x2d, 0x8f, 0xf3, 0x49, 0xde, 0xdd, 0xa0, 0x2b, 0x30, 0x59, 0x6f, + 0x90, 0x32, 0x29, 0x11, 0xc6, 0x68, 0x83, 0xcd, 0xc7, 0x64, 0xe1, 0x1c, 0x13, 0xb1, 0x47, 0x5d, + 0x34, 0xca, 0x62, 0x95, 0x96, 0x0e, 0x4c, 0x4b, 0x1a, 0x93, 0x79, 0x48, 0x4a, 0x99, 0x6a, 0x48, + 0x68, 0x19, 0x40, 0xa9, 0xc8, 0xdf, 0x42, 0xb5, 0xe3, 0x09, 0x29, 0x91, 0x8d, 0x7e, 0xdb, 0x1c, + 0x8b, 0x99, 0x35, 0x1f, 0x97, 0xd0, 0x53, 0xb6, 0x1a, 0x68, 0xb6, 0x19, 0x68, 0xf6, 0x9e, 0x19, + 0x68, 0xb9, 0x84, 0x28, 0x91, 0xc7, 0x3f, 0x64, 0x22, 0xda, 0x89, 0x38, 0x09, 0x7d, 0xe9, 0xc4, + 0x9f, 0xf3, 0xd2, 0x13, 0x3d, 0x2f, 0x8d, 0x2c, 0x38, 0xa5, 0xe0, 0xd7, 0x70, 0xbb, 0x20, 0x1e, + 0x17, 0x02, 0x19, 0xb8, 0x85, 0xdb, 0xbb, 0x98, 0xbd, 0x1d, 0x4b, 0x8c, 0xce, 0x44, 0xf3, 0x09, + 0xde, 0x2e, 0x78, 0x7e, 0x99, 0xb4, 0xad, 0xf3, 0xba, 0x8f, 0x75, 0xde, 0xbc, 0xdb, 0x64, 0xca, + 0x98, 0x63, 0x53, 0xdc, 0x62, 0x6d, 0x7d, 0x19, 0xd5, 0xa3, 0x5b, 0x2a, 0xe7, 0x84, 0xd7, 0x40, + 0x8d, 0xf0, 0xb6, 0xf9, 0xd5, 0x8f, 0xab, 0x11, 0xde, 0x66, 0xaf, 0x55, 0x23, 0x7f, 0x3d, 0xf2, + 0xc9, 0x8f, 0x6c, 0x5d, 0xd4, 0x1c, 0x29, 0xf8, 0x4e, 0xc7, 0xbc, 0xeb, 0x99, 0xce, 0x98, 0x66, + 0xe4, 0x1a, 0x31, 0xdd, 0xde, 0x7a, 0x14, 0xe9, 0xcc, 0x60, 0x2d, 0xd7, 0x3e, 0xfe, 0x0d, 0x09, + 0xd1, 0x99, 0x0b, 0xfb, 0x44, 0x8f, 0xb9, 0xdc, 0xc2, 0xf7, 0xcf, 0x33, 0x67, 0xd4, 0x15, 0x59, + 0xf9, 0xc0, 0xf6, 0xa8, 0x53, 0xc3, 0xbc, 0x62, 0x5f, 0xf7, 0xb9, 0x98, 0xcf, 0xd2, 0x1a, 0xbd, + 0x01, 0x53, 0xc6, 0xaa, 0xd0, 0xf4, 0xbd, 0xa2, 0x1e, 0xd1, 0xc7, 0xd9, 0x4e, 0x6a, 0xdb, 0x77, + 0x85, 0xba, 0x75, 0x05, 0x16, 0x25, 0x9c, 0x6b, 0x4d, 0x7f, 0x8f, 0x1e, 0x10, 0xff, 0x16, 0xae, + 0xd7, 0x3d, 0xdf, 0x35, 0x25, 0x38, 0x0b, 0x63, 0x5c, 0x88, 0xcd, 0xe4, 0x95, 0x9b, 0xc0, 0x98, + 0xfa, 0x50, 0xf3, 0xac, 0x01, 0x73, 0x7d, 0xab, 0x2d, 0x98, 0xd8, 0x6f, 0xfa, 0x85, 0xae, 0x8f, + 0x64, 0x76, 0x36, 0x58, 0x92, 0xc6, 0x2e, 0x9f, 0xd8, 0xd7, 0xab, 0xae, 0xf3, 0xec, 0x57, 0x93, + 0x30, 0x26, 0xbd, 0xa3, 0x87, 0x11, 0x80, 0x2e, 0x37, 0x45, 0x56, 0xd0, 0x45, 0x38, 0xef, 0x4d, + 0xad, 0x1d, 0xab, 0xa3, 0xe0, 0x59, 0x17, 0x3e, 0xfd, 0xf6, 0xa7, 0x2f, 0x46, 0xd7, 0xd1, 0xdf, + 0x1d, 0x91, 0x8c, 0x46, 0xb3, 0x43, 0xe1, 0x05, 0x07, 0x55, 0xba, 0xce, 0x03, 0x5d, 0x8a, 0x47, + 0xe8, 0x49, 0x04, 0x66, 0xfa, 0x29, 0x20, 0xda, 0x1c, 0x88, 0x33, 0x84, 0x73, 0xa6, 0xce, 0xfd, + 0x0e, 0x4d, 0x8d, 0xeb, 0xbf, 0x12, 0xd7, 0x16, 0x72, 0xfa, 0x70, 0xb5, 0x8c, 0x41, 0x17, 0x5d, + 0x90, 0xc6, 0x1e, 0xa1, 0xfb, 0x10, 0xcf, 0x19, 0xea, 0x36, 0x10, 0xae, 0x97, 0x31, 0xa6, 0x56, + 0x86, 0x2b, 0x68, 0x18, 0xe7, 0x24, 0x8c, 0x35, 0xb4, 0xda, 0x07, 0x43, 0xf3, 0x3f, 0x16, 0xc8, + 0xcd, 0x27, 0x10, 0xd7, 0xac, 0x2d, 0x24, 0x70, 0x2f, 0x39, 0x0c, 0x09, 0xdc, 0x47, 0xf8, 0x2c, + 0x5b, 0x06, 0xde, 0x44, 0xeb, 0x7d, 0x81, 0x99, 0xd2, 0xeb, 0xc6, 0x75, 0x1e, 0x1c, 0x90, 0xc3, + 0x23, 0x74, 0x00, 0x31, 0xc1, 0xe6, 0xd0, 0xd2, 0x80, 0xe7, 0x00, 0x39, 0x4c, 0x2d, 0x0f, 0x39, + 0xd5, 0x41, 0xd7, 0x65, 0xd0, 0x15, 0x94, 0xee, 0x0b, 0x2a, 0xb8, 0x60, 0xf0, 0xaa, 0x15, 0x18, + 0x57, 0x6c, 0x06, 0xa5, 0x07, 0x1c, 0xf6, 0x10, 0xa5, 0x54, 0x66, 0xe8, 0xb9, 0x0e, 0xb9, 0x2c, + 0x43, 0xce, 0xa1, 0x33, 0x7d, 0x21, 0x15, 0x3f, 0x42, 0x1e, 0xc4, 0x35, 0x3d, 0x42, 0xa9, 0xa0, + 0xab, 0x5e, 0xce, 0x94, 0x5a, 0x1d, 0x3e, 0x1a, 0x4c, 0xa0, 0x8c, 0x0c, 0xb4, 0x80, 0xe6, 0x42, + 0x0a, 0xbd, 0x24, 0xfc, 0x53, 0x48, 0x06, 0x08, 0xcd, 0xb1, 0xe1, 0x7a, 0x6e, 0x15, 0xc2, 0x82, + 0xac, 0x35, 0x19, 0x6c, 0x19, 0x2d, 0xf6, 0x07, 0xd3, 0xba, 0xa2, 0xc3, 0xa2, 0x1a, 0xc4, 0xf5, + 0x78, 0x0c, 0x29, 0x98, 0x5e, 0xb2, 0x14, 0x52, 0x30, 0x7d, 0x93, 0x75, 0xe8, 0xfd, 0xd4, 0x48, + 0xe4, 0x6d, 0x74, 0x08, 0xd0, 0x6d, 0xdc, 0x21, 0x0d, 0x64, 0x60, 0xfa, 0x86, 0x34, 0x90, 0xc1, + 0xce, 0x6f, 0x59, 0x32, 0xee, 0x12, 0x4a, 0x85, 0xc6, 0x95, 0xe3, 0x03, 0xdd, 0x83, 0x09, 0x35, + 0x79, 0x45, 0x9e, 0xff, 0x80, 0xbb, 0xae, 0xca, 0x98, 0x8b, 0x68, 0x21, 0x34, 0xa6, 0x7c, 0xcd, + 0x9a, 0x68, 0x03, 0x6a, 0x42, 0x84, 0xb5, 0x81, 0xe0, 0x44, 0x0a, 0x6d, 0x03, 0x3d, 0xa3, 0x69, + 0x68, 0x72, 0xcd, 0xe4, 0x41, 0x8f, 0x22, 0x30, 0xdd, 0x37, 0x01, 0xd0, 0xc6, 0x80, 0xdb, 0xf0, + 0x11, 0x93, 0xda, 0x3c, 0x59, 0x51, 0xe3, 0xd8, 0x90, 0x38, 0x56, 0x51, 0xa6, 0x0f, 0xc7, 0x7e, + 0xd3, 0x97, 0x03, 0xc6, 0x79, 0x20, 0x3f, 0x47, 0xb9, 0x37, 0x9f, 0xbe, 0x48, 0x47, 0x9e, 0xbd, + 0x48, 0x47, 0x7e, 0x7c, 0x91, 0x8e, 0x3c, 0x7e, 0x99, 0x1e, 0x79, 0xf6, 0x32, 0x3d, 0xf2, 0xdd, + 0xcb, 0xf4, 0xc8, 0x07, 0xeb, 0x01, 0x12, 0x71, 0x5b, 0x3a, 0xd9, 0x16, 0x14, 0xc0, 0x38, 0x6c, + 0x65, 0x9d, 0xb6, 0xf0, 0x5a, 0x1c, 0x97, 0x9c, 0xe5, 0xd2, 0x6f, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xe6, 0x31, 0x27, 0xb5, 0x28, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2853,6 +2857,18 @@ func (m *QueryBaseFeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.BaseFeeUnibi != nil { + { + size := m.BaseFeeUnibi.Size() + i -= size + if _, err := m.BaseFeeUnibi.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if m.BaseFee != nil { { size := m.BaseFee.Size() @@ -3323,6 +3339,10 @@ func (m *QueryBaseFeeResponse) Size() (n int) { l = m.BaseFee.Size() n += 1 + l + sovQuery(uint64(l)) } + if m.BaseFeeUnibi != nil { + l = m.BaseFeeUnibi.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -5896,6 +5916,42 @@ func (m *QueryBaseFeeResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseFeeUnibi", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.BaseFeeUnibi = &v + if err := m.BaseFeeUnibi.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/evm/statedb/config.go b/x/evm/statedb/config.go index a4d5a29d0..c75cdc179 100644 --- a/x/evm/statedb/config.go +++ b/x/evm/statedb/config.go @@ -4,22 +4,22 @@ package statedb import ( "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/params" + gethcommon "github.com/ethereum/go-ethereum/common" + gethparams "github.com/ethereum/go-ethereum/params" "github.com/NibiruChain/nibiru/v2/x/evm" ) // TxConfig encapsulates the readonly information of current tx for `StateDB`. type TxConfig struct { - BlockHash common.Hash // hash of current block - TxHash common.Hash // hash of current tx - TxIndex uint // the index of current transaction - LogIndex uint // the index of next log within current block + BlockHash gethcommon.Hash // hash of current block + TxHash gethcommon.Hash // hash of current tx + TxIndex uint // the index of current transaction + LogIndex uint // the index of next log within current block } // NewTxConfig returns a TxConfig -func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { +func NewTxConfig(bhash, thash gethcommon.Hash, txIndex, logIndex uint) TxConfig { return TxConfig{ BlockHash: bhash, TxHash: thash, @@ -30,21 +30,29 @@ func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { // NewEmptyTxConfig construct an empty TxConfig, // used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`. -func NewEmptyTxConfig(bhash common.Hash) TxConfig { +func NewEmptyTxConfig(bhash gethcommon.Hash) TxConfig { return TxConfig{ BlockHash: bhash, - TxHash: common.Hash{}, + TxHash: gethcommon.Hash{}, TxIndex: 0, LogIndex: 0, } } -// EVMConfig encapsulates common parameters needed to create an EVM to execute a message -// It's mainly to reduce the number of method parameters +// EVMConfig encapsulates parameters needed to create an instance of the EVM +// ("go-ethereum/core/vm.EVM"). type EVMConfig struct { Params evm.Params - ChainConfig *params.ChainConfig - CoinBase common.Address - // BaseFee is the EVM base fee in units of micronibi per gas - BaseFee *big.Int + ChainConfig *gethparams.ChainConfig + + // BlockCoinbase: In Ethereum, the coinbase (or "benficiary") is the address that + // proposed the current block. It corresponds to the [COINBASE op code] + // (the "block.coinbase" stack output). + // + // [COINBASE op code]: https://ethereum.org/en/developers/docs/evm/opcodes/ + BlockCoinbase gethcommon.Address + + // BaseFeeWei is the EVM base fee in units of wei per gas. The term "base + // fee" comes from EIP-1559. + BaseFeeWei *big.Int } diff --git a/x/evm/tx_data_dynamic_fee_test.go b/x/evm/tx_data_dynamic_fee_test.go index f9b73ecce..a0f77c7a3 100644 --- a/x/evm/tx_data_dynamic_fee_test.go +++ b/x/evm/tx_data_dynamic_fee_test.go @@ -577,7 +577,7 @@ func (suite *Suite) TestDynamicFeeTxEffectiveGasPrice() { GasFeeCap: &gasFeeCap, } }, - baseFeeWei: evm.NativeToWei(evm.BASE_FEE_MICRONIBI), + baseFeeWei: evm.BASE_FEE_WEI, exp: evm.NativeToWei(big.NewInt(6)), }, { @@ -590,7 +590,7 @@ func (suite *Suite) TestDynamicFeeTxEffectiveGasPrice() { GasFeeCap: &gasFeeCap, } }, - baseFeeWei: evm.NativeToWei(evm.BASE_FEE_MICRONIBI), + baseFeeWei: evm.BASE_FEE_WEI, exp: evm.NativeToWei(big.NewInt(2)), }, { @@ -603,7 +603,7 @@ func (suite *Suite) TestDynamicFeeTxEffectiveGasPrice() { GasFeeCap: &gasFeeCap, } }, - baseFeeWei: evm.NativeToWei(evm.BASE_FEE_MICRONIBI), + baseFeeWei: evm.BASE_FEE_WEI, exp: evm.NativeToWei(big.NewInt(1)), }, } From d4e2e6efe84cc2db16f414ee7a0617c4ef557564 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 13 Oct 2024 00:24:51 -0500 Subject: [PATCH 3/6] fix e2e test and address coderabbitai PR comments --- app/evmante/evmante_can_transfer.go | 23 ++++++++++++----------- app/evmante/interfaces.go | 3 ++- e2e/evm/test/eth_queries.test.ts | 2 +- eth/rpc/backend/backend.go | 13 ++++++++----- eth/rpc/backend/chain_info_test.go | 2 +- justfile | 9 +++++++-- x/evm/keeper/gas_fees_test.go | 2 +- x/evm/keeper/grpc_query.go | 6 +++--- 8 files changed, 35 insertions(+), 25 deletions(-) diff --git a/app/evmante/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go index cb271e36a..1edc798d9 100644 --- a/app/evmante/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -37,8 +37,8 @@ func (ctd CanTransferDecorator) AnteHandle( "invalid message type %T, expected %T", msg, (*evm.MsgEthereumTx)(nil), ) } - baseFeeMicronibiPerGas := ctd.EVMKeeper.BaseFeeMicronibiPerGas(ctx) - baseFeeWeiPerGas := evm.NativeToWei(baseFeeMicronibiPerGas) + + baseFeeWeiPerGas := evm.NativeToWei(ctd.EVMKeeper.BaseFeeMicronibiPerGas(ctx)) coreMsg, err := msgEthTx.AsMessage(signer, baseFeeWeiPerGas) if err != nil { @@ -48,26 +48,27 @@ func (ctd CanTransferDecorator) AnteHandle( ) } - if baseFeeMicronibiPerGas == nil { + if baseFeeWeiPerGas == nil { return ctx, errors.Wrap( evm.ErrInvalidBaseFee, - "base fee is supported but evm block context value is nil", + "base fee is nil for this block.", ) } - if coreMsg.GasFeeCap().Cmp(baseFeeMicronibiPerGas) < 0 { + if coreMsg.GasFeeCap().Cmp(baseFeeWeiPerGas) < 0 { return ctx, errors.Wrapf( sdkerrors.ErrInsufficientFee, - "max fee per gas less than block base fee (%s < %s)", - coreMsg.GasFeeCap(), baseFeeMicronibiPerGas, + "gas fee cap (wei) less than block base fee (wei); (%s < %s)", + coreMsg.GasFeeCap(), baseFeeWeiPerGas, ) } - // NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below cfg := &statedb.EVMConfig{ - ChainConfig: ethCfg, - Params: params, + ChainConfig: ethCfg, + Params: params, + // Note that we use an empty coinbase here because the field is not + // used during this Ante Handler. BlockCoinbase: gethcommon.Address{}, - BaseFeeWei: baseFeeMicronibiPerGas, + BaseFeeWei: baseFeeWeiPerGas, } stateDB := statedb.New( diff --git a/app/evmante/interfaces.go b/app/evmante/interfaces.go index 1f433dd21..46e3af6e1 100644 --- a/app/evmante/interfaces.go +++ b/app/evmante/interfaces.go @@ -2,8 +2,9 @@ package evmante import ( - evmkeeper "github.com/NibiruChain/nibiru/v2/x/evm/keeper" "github.com/cosmos/cosmos-sdk/types/tx" + + evmkeeper "github.com/NibiruChain/nibiru/v2/x/evm/keeper" ) type EVMKeeper = evmkeeper.Keeper diff --git a/e2e/evm/test/eth_queries.test.ts b/e2e/evm/test/eth_queries.test.ts index 3189ede3c..c45b0e452 100644 --- a/e2e/evm/test/eth_queries.test.ts +++ b/e2e/evm/test/eth_queries.test.ts @@ -49,7 +49,7 @@ describe("eth queries", () => { it("eth_gasPrice", async () => { const gasPrice = await provider.send("eth_gasPrice", []) expect(gasPrice).toBeDefined() - expect(gasPrice).toEqual(hexify(1)) + expect(gasPrice).toEqual(hexify(1000000000000)) // 1 micronibi == 10^{12} wei }) it("eth_getBalance", async () => { diff --git a/eth/rpc/backend/backend.go b/eth/rpc/backend/backend.go index 047692b09..ecbe94f5f 100644 --- a/eth/rpc/backend/backend.go +++ b/eth/rpc/backend/backend.go @@ -57,10 +57,13 @@ func NewBackend( // CosmosBackend: Currently unused. Backend functionality for the shared // "cosmos" RPC namespace. Implements [BackendI] in combination with [Backend]. -// TODO: feat(eth): Implement the cosmos JSON-RPC defined by Wallet Connect V2: -// https://docs.walletconnect.com/2.0/json-rpc/cosmos. +// TODO: feat(eth): Implement the cosmos JSON-RPC defined by [Wallet Connect V2]. +// [Reference ticket]. +// +// [Wallet Connect V2]: https://docs.walletconnect.com/2.0/json-rpc/cosmos. +// [Reference ticket]: https://github.com/NibiruChain/nibiru/issues/2077 type CosmosBackend interface { - // TODO: for Wallet Connect V2: GetAccounts() - // TODO: for Wallet Connect V2: SignDirect() - // TODO: for Wallet Connect V2: SignAmino() + // for Wallet Connect V2: GetAccounts() + // for Wallet Connect V2: SignDirect() + // for Wallet Connect V2: SignAmino() } diff --git a/eth/rpc/backend/chain_info_test.go b/eth/rpc/backend/chain_info_test.go index 75b6c06d4..5056b5637 100644 --- a/eth/rpc/backend/chain_info_test.go +++ b/eth/rpc/backend/chain_info_test.go @@ -20,7 +20,7 @@ func (s *BackendSuite) TestChainConfig() { s.Require().Equal(int64(0), config.LondonBlock.Int64()) } -func (s *BackendSuite) TestBaseFee() { +func (s *BackendSuite) TestBaseFeeWei() { resBlock, err := s.backend.TendermintBlockResultByNumber(transferTxBlockNumber.TmHeight()) s.Require().NoError(err) baseFeeWei, err := s.backend.BaseFeeWei(resBlock) diff --git a/justfile b/justfile index 9a3bddca7..896265ad9 100644 --- a/justfile +++ b/justfile @@ -50,7 +50,13 @@ localnet *PASS_FLAGS: # Clears the logs directory log-clear: #!/usr/bin/env bash - rm logs/* + if [ -d "logs" ] && [ "$(ls -A logs)" ]; then + rm logs/* && echo "Logs cleared successfully." + elif [ ! -d "logs" ]; then + echo "Logs directory does not exist. Nothing to clear." + else + echo "Logs directory is already empty." + fi # Runs "just localnet" with logging (logs/localnet.txt) log-localnet: @@ -70,7 +76,6 @@ test-e2e: log_info "Make sure the localnet is running! (just localnet)" cd e2e/evm - nvm use just test diff --git a/x/evm/keeper/gas_fees_test.go b/x/evm/keeper/gas_fees_test.go index 2afd9beec..e9a1232fc 100644 --- a/x/evm/keeper/gas_fees_test.go +++ b/x/evm/keeper/gas_fees_test.go @@ -202,7 +202,7 @@ func (s *Suite) TestRefundGas() { func(deps *evmtest.TestDeps) testCase { fundFeeCollectorEvmBal(deps, s, feeCollectorInitialBalance) return testCase{ - name: "sad: geth tx gas, negative ?? base fee (impossible but here for compelteness", + name: "sad: geth tx gas, negative base fee (impossible but here for completeness", msgFrom: deps.Sender.EthAddr, leftoverGas: gethparams.TxGas, weiPerGas: new(big.Int).Neg(evm.BASE_FEE_WEI), diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index c8dfd7fa0..1ae3c19be 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -681,9 +681,9 @@ func (k Keeper) TraceBlock( } // compute and use base fee of height that is being traced - baseFeeMicronibiPerGas := k.BaseFeeMicronibiPerGas(ctx) - if baseFeeMicronibiPerGas != nil { - cfg.BaseFeeWei = baseFeeMicronibiPerGas + if baseFeeMicronibiPerGas := k.BaseFeeMicronibiPerGas(ctx); baseFeeMicronibiPerGas != nil { + baseFeeWeiPerGas := evm.NativeToWei(baseFeeMicronibiPerGas) + cfg.BaseFeeWei = baseFeeWeiPerGas } var tracerConfig json.RawMessage if req.TraceConfig != nil && req.TraceConfig.TracerConfig != nil { From ddaaee7778d365a0038074634a6333e497827a13 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 13 Oct 2024 04:24:06 -0500 Subject: [PATCH 4/6] red, green, refactor --- app/ante/gas.go | 5 ++++- x/evm/json_tx_args_test.go | 4 ++-- x/evm/keeper/gas_fees.go | 4 +++- x/evm/keeper/keeper.go | 6 ++++++ x/evm/keeper/msg_server.go | 6 +++--- x/evm/keeper/vm_config.go | 3 +-- x/evm/tx_data.go | 2 +- x/evm/tx_data_access_list.go | 4 ++-- x/evm/tx_data_dynamic_fee.go | 4 ++-- x/evm/tx_data_dynamic_fee_test.go | 2 +- x/evm/tx_data_legacy.go | 4 ++-- x/evm/tx_data_legacy_test.go | 2 +- 12 files changed, 28 insertions(+), 18 deletions(-) diff --git a/app/ante/gas.go b/app/ante/gas.go index 7b4c2da98..c6559c2a4 100644 --- a/app/ante/gas.go +++ b/app/ante/gas.go @@ -35,8 +35,11 @@ func (g *fixedGasMeter) GasRemaining() storetypes.Gas { return g.consumed } +// ConsumeGas is a no-op because the fixed gas meter stays fixed. func (g *fixedGasMeter) ConsumeGas(types.Gas, string) {} -func (g *fixedGasMeter) RefundGas(types.Gas, string) {} + +// RefundGas is a no-op because the fixed gas meter stays fixed. +func (g *fixedGasMeter) RefundGas(types.Gas, string) {} func (g *fixedGasMeter) IsPastLimit() bool { return false diff --git a/x/evm/json_tx_args_test.go b/x/evm/json_tx_args_test.go index 026fec314..3a99a8f06 100644 --- a/x/evm/json_tx_args_test.go +++ b/x/evm/json_tx_args_test.go @@ -104,7 +104,7 @@ func (suite *Suite) TestToMessageEVM() { name string txArgs evm.JsonTxArgs globalGasCap uint64 - baseFee *big.Int + baseFeeWei *big.Int expError bool }{ { @@ -216,7 +216,7 @@ func (suite *Suite) TestToMessageEVM() { }, } for _, tc := range testCases { - res, err := tc.txArgs.ToMessage(tc.globalGasCap, tc.baseFee) + res, err := tc.txArgs.ToMessage(tc.globalGasCap, tc.baseFeeWei) if tc.expError { suite.Require().NotNil(err) diff --git a/x/evm/keeper/gas_fees.go b/x/evm/keeper/gas_fees.go index aff670907..01c72034c 100644 --- a/x/evm/keeper/gas_fees.go +++ b/x/evm/keeper/gas_fees.go @@ -52,7 +52,9 @@ func (k *Keeper) RefundGas( case -1: // Should be impossible since leftoverGas is a uint64. Reaching this case // would imply a critical error in the effective gas calculation. - return errors.Wrapf(evm.ErrInvalidRefund, "refunded amount value cannot be negative %d", leftoverMicronibi.Int64()) + return errors.Wrapf(evm.ErrInvalidRefund, + "refunded amount value cannot be negative %s", leftoverMicronibi, + ) case 1: refundedCoins := sdk.Coins{sdk.NewCoin(evm.EVMBankDenom, sdkmath.NewIntFromBigInt(leftoverMicronibi))} diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 08d80383e..49ea0c9bf 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -122,6 +122,12 @@ func (k Keeper) BaseFeeMicronibiPerGas(_ sdk.Context) *big.Int { return evm.BASE_FEE_MICRONIBI } +// BaseFeeWeiPerGas is the same as BaseFeeMicronibiPerGas, except its in units of +// wei per gas. +func (k Keeper) BaseFeeWeiPerGas(_ sdk.Context) *big.Int { + return evm.NativeToWei(k.BaseFeeMicronibiPerGas(sdk.Context{})) +} + // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", evm.ModuleName) diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index f926a0b6a..44cb38fc3 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -29,14 +29,14 @@ import ( var _ evm.MsgServer = &Keeper{} func (k *Keeper) EthereumTx( - goCtx context.Context, msg *evm.MsgEthereumTx, + goCtx context.Context, txMsg *evm.MsgEthereumTx, ) (resp *evm.MsgEthereumTxResponse, err error) { - if err := msg.ValidateBasic(); err != nil { + if err := txMsg.ValidateBasic(); err != nil { return resp, errors.Wrap(err, "EthereumTx validate basic failed") } ctx := sdk.UnwrapSDKContext(goCtx) - resp, err = k.ApplyEvmTx(ctx, msg) + resp, err = k.ApplyEvmTx(ctx, txMsg) if err != nil { return nil, errors.Wrap(err, "failed to apply transaction") } diff --git a/x/evm/keeper/vm_config.go b/x/evm/keeper/vm_config.go index 59c380e08..241cae816 100644 --- a/x/evm/keeper/vm_config.go +++ b/x/evm/keeper/vm_config.go @@ -27,12 +27,11 @@ func (k *Keeper) GetEVMConfig( return nil, errors.Wrap(err, "failed to obtain coinbase address") } - baseFeeMicronibiPerGas := k.BaseFeeMicronibiPerGas(ctx) return &statedb.EVMConfig{ Params: params, ChainConfig: ethCfg, BlockCoinbase: coinbase, - BaseFeeWei: baseFeeMicronibiPerGas, + BaseFeeWei: k.BaseFeeWeiPerGas(ctx), }, nil } diff --git a/x/evm/tx_data.go b/x/evm/tx_data.go index f7b47f22b..c3b21a026 100644 --- a/x/evm/tx_data.go +++ b/x/evm/tx_data.go @@ -93,7 +93,7 @@ type TxData interface { // effective gasPrice/fee/cost according to current base fee EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.Int EffectiveFeeWei(baseFeeWei *big.Int) *big.Int - EffectiveCost(baseFeeWei *big.Int) *big.Int + EffectiveCostWei(baseFeeWei *big.Int) *big.Int } // NOTE: All non-protected transactions (i.e. non EIP155 signed) will fail if the diff --git a/x/evm/tx_data_access_list.go b/x/evm/tx_data_access_list.go index 82adcbeda..fe5a59177 100644 --- a/x/evm/tx_data_access_list.go +++ b/x/evm/tx_data_access_list.go @@ -296,8 +296,8 @@ func (tx AccessListTx) EffectiveFeeWei(baseFeeWei *big.Int) *big.Int { return priceTimesGas(tx.EffectiveGasPriceWeiPerGas(baseFeeWei), tx.GetGas()) } -// EffectiveCost is the same as Cost for AccessListTx -func (tx AccessListTx) EffectiveCost(baseFeeWei *big.Int) *big.Int { +// EffectiveCostWei is the same as Cost for AccessListTx +func (tx AccessListTx) EffectiveCostWei(baseFeeWei *big.Int) *big.Int { return cost( tx.EffectiveFeeWei(baseFeeWei), tx.GetValueWei(), ) diff --git a/x/evm/tx_data_dynamic_fee.go b/x/evm/tx_data_dynamic_fee.go index 7f710a70a..111abba63 100644 --- a/x/evm/tx_data_dynamic_fee.go +++ b/x/evm/tx_data_dynamic_fee.go @@ -306,7 +306,7 @@ func (tx DynamicFeeTx) EffectiveFeeWei(baseFeeWei *big.Int) *big.Int { return priceTimesGas(tx.EffectiveGasPriceWeiPerGas(baseFeeWei), tx.GasLimit) } -// EffectiveCost returns amount + effective_gasprice * gaslimit. -func (tx DynamicFeeTx) EffectiveCost(baseFeeWei *big.Int) *big.Int { +// EffectiveCostWei returns amount + effective_gasprice * gaslimit. +func (tx DynamicFeeTx) EffectiveCostWei(baseFeeWei *big.Int) *big.Int { return cost(tx.EffectiveFeeWei(baseFeeWei), tx.GetValueWei()) } diff --git a/x/evm/tx_data_dynamic_fee_test.go b/x/evm/tx_data_dynamic_fee_test.go index a0f77c7a3..1136af0e2 100644 --- a/x/evm/tx_data_dynamic_fee_test.go +++ b/x/evm/tx_data_dynamic_fee_test.go @@ -663,7 +663,7 @@ func (suite *Suite) TestDynamicFeeTxEffectiveCost() { } for _, tc := range testCases { - actual := tc.tx.EffectiveCost(tc.baseFee) + actual := tc.tx.EffectiveCostWei(tc.baseFee) suite.Require().Equal(tc.exp, actual, tc.name) } diff --git a/x/evm/tx_data_legacy.go b/x/evm/tx_data_legacy.go index efa3f9d57..73c15ffaf 100644 --- a/x/evm/tx_data_legacy.go +++ b/x/evm/tx_data_legacy.go @@ -200,8 +200,8 @@ func (tx LegacyTx) EffectiveFeeWei(baseFeeWei *big.Int) *big.Int { return priceTimesGas(tx.EffectiveGasPriceWeiPerGas(baseFeeWei), tx.GetGas()) } -// EffectiveCost is the same as Cost for LegacyTx -func (tx LegacyTx) EffectiveCost(baseFeeWei *big.Int) *big.Int { +// EffectiveCostWei is the same as Cost for LegacyTx +func (tx LegacyTx) EffectiveCostWei(baseFeeWei *big.Int) *big.Int { txFee := tx.EffectiveFeeWei(baseFeeWei) return cost(txFee, tx.GetValueWei()) } diff --git a/x/evm/tx_data_legacy_test.go b/x/evm/tx_data_legacy_test.go index 85f83df4f..ae4da41ba 100644 --- a/x/evm/tx_data_legacy_test.go +++ b/x/evm/tx_data_legacy_test.go @@ -423,7 +423,7 @@ func (suite *Suite) TestLegacyTxEffectiveCost() { } for _, tc := range testCases { - actual := tc.tx.EffectiveCost(tc.baseFee) + actual := tc.tx.EffectiveCostWei(tc.baseFee) suite.Require().Equal(tc.exp, actual, tc.name) } From 3e9cbc649722e898b5dcfad3d08b8fb74cbe84cb Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 13 Oct 2024 04:59:33 -0500 Subject: [PATCH 5/6] red, green, refactor --- app/evmante/evmante_can_transfer.go | 3 ++- eth/rpc/rpcapi/eth_api_test.go | 2 +- x/evm/keeper/msg_ethereum_tx_test.go | 4 ++-- x/evm/keeper/msg_server.go | 30 +++++++++++++--------------- x/evm/msg.go | 8 ++++++++ x/evm/tx_data.go | 1 + x/evm/tx_data_access_list.go | 4 ++++ x/evm/tx_data_dynamic_fee.go | 4 ++++ x/evm/tx_data_legacy.go | 4 ++++ 9 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/evmante/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go index 1edc798d9..8af24d2f2 100644 --- a/app/evmante/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -54,7 +54,8 @@ func (ctd CanTransferDecorator) AnteHandle( "base fee is nil for this block.", ) } - if coreMsg.GasFeeCap().Cmp(baseFeeWeiPerGas) < 0 { + + if msgEthTx.EffectiveGasCapWei(baseFeeWeiPerGas).Cmp(baseFeeWeiPerGas) < 0 { return ctx, errors.Wrapf( sdkerrors.ErrInsufficientFee, "gas fee cap (wei) less than block base fee (wei); (%s < %s)", diff --git a/eth/rpc/rpcapi/eth_api_test.go b/eth/rpc/rpcapi/eth_api_test.go index 1d9eb3eb6..e20513f5e 100644 --- a/eth/rpc/rpcapi/eth_api_test.go +++ b/eth/rpc/rpcapi/eth_api_test.go @@ -385,7 +385,7 @@ func (s *NodeSuite) Test_SmartContract() { // This query will succeed only if a receipt is found _, err = s.ethClient.TransactionReceipt(blankCtx, txHash) - s.Require().Errorf(err, "receipt for txHash: %s", txHash.Hex()) + s.Require().NoErrorf(err, "receipt for txHash: %s", txHash.Hex()) // This query succeeds if no receipt is found _, err = s.ethAPI.GetTransactionReceipt(txHash) diff --git a/x/evm/keeper/msg_ethereum_tx_test.go b/x/evm/keeper/msg_ethereum_tx_test.go index 374f06c57..0c2de7a39 100644 --- a/x/evm/keeper/msg_ethereum_tx_test.go +++ b/x/evm/keeper/msg_ethereum_tx_test.go @@ -32,7 +32,7 @@ func (s *Suite) TestMsgEthereumTx_CreateContract() { deps := evmtest.NewTestDeps() ethAcc := deps.Sender - // Leftover gas fee is refunded within ApplyEvmTx from the FeeCollector + // Leftover gas fee is refunded within EthereumTx from the FeeCollector // so, the module must have some coins err := testapp.FundModuleAccount( deps.App.BankKeeper, @@ -115,7 +115,7 @@ func (s *Suite) TestMsgEthereumTx_ExecuteContract() { deps := evmtest.NewTestDeps() ethAcc := deps.Sender - // Leftover gas fee is refunded within ApplyEvmTx from the FeeCollector + // Leftover gas fee is refunded within EthereumTx from the FeeCollector // so, the module must have some coins err := testapp.FundModuleAccount( deps.App.BankKeeper, diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 44cb38fc3..27e80a610 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -30,22 +30,20 @@ var _ evm.MsgServer = &Keeper{} func (k *Keeper) EthereumTx( goCtx context.Context, txMsg *evm.MsgEthereumTx, -) (resp *evm.MsgEthereumTxResponse, err error) { +) (evmResp *evm.MsgEthereumTxResponse, err error) { + // This is a `defer` pattern to add behavior that runs in the case that the error is + // non-nil, creating a concise way to add extra information. + defer func() { + if err != nil { + err = fmt.Errorf("EthereumTx error: %w", err) + } + }() + if err := txMsg.ValidateBasic(); err != nil { - return resp, errors.Wrap(err, "EthereumTx validate basic failed") + return evmResp, errors.Wrap(err, "EthereumTx validate basic failed") } ctx := sdk.UnwrapSDKContext(goCtx) - resp, err = k.ApplyEvmTx(ctx, txMsg) - if err != nil { - return nil, errors.Wrap(err, "failed to apply transaction") - } - return resp, nil -} - -func (k *Keeper) ApplyEvmTx( - ctx sdk.Context, txMsg *evm.MsgEthereumTx, -) (*evm.MsgEthereumTxResponse, error) { tx := txMsg.AsTransaction() evmConfig, err := k.GetEVMConfig(ctx, ctx.BlockHeader().ProposerAddress, k.EthChainID(ctx)) @@ -64,7 +62,7 @@ func (k *Keeper) ApplyEvmTx( tmpCtx, commit := ctx.CacheContext() // pass true to commit the StateDB - evmResp, err := k.ApplyEvmMsg(tmpCtx, msg, nil, true, evmConfig, txConfig) + evmResp, err = k.ApplyEvmMsg(tmpCtx, msg, nil, true, evmConfig, txConfig) if err != nil { // when a transaction contains multiple msg, as long as one of the msg fails // all gas will be deducted. so is not msg.Gas() @@ -114,7 +112,7 @@ func (k *Keeper) ApplyEvmTx( } weiPerGas := txMsg.EffectiveGasPriceWeiPerGas(evmConfig.BaseFeeWei) if err = k.RefundGas(ctx, msg.From(), refundGas, weiPerGas); err != nil { - return nil, errors.Wrapf(err, "failed to refund leftover gas to sender %s", msg.From()) + return nil, errors.Wrapf(err, "error refunding leftover gas to sender %s", msg.From()) } if len(receipt.Logs) > 0 { @@ -126,7 +124,7 @@ func (k *Keeper) ApplyEvmTx( totalGasUsed, err := k.AddToBlockGasUsed(ctx, evmResp.GasUsed) if err != nil { - return nil, errors.Wrap(err, "failed to add transient gas used") + return nil, errors.Wrap(err, "error adding transient gas used to block") } // reset the gas meter for current cosmos transaction @@ -134,7 +132,7 @@ func (k *Keeper) ApplyEvmTx( err = k.EmitEthereumTxEvents(ctx, tx, msg, evmResp, contractAddr) if err != nil { - return nil, errors.Wrap(err, "failed to emit ethereum tx events") + return nil, errors.Wrap(err, "error emitting ethereum tx events") } blockTxIdx := uint64(txConfig.TxIndex) + 1 diff --git a/x/evm/msg.go b/x/evm/msg.go index 3ab4ff024..8406ad80a 100644 --- a/x/evm/msg.go +++ b/x/evm/msg.go @@ -286,6 +286,14 @@ func (msg MsgEthereumTx) EffectiveGasPriceWeiPerGas(baseFeeWei *big.Int) *big.In return txData.EffectiveGasPriceWeiPerGas(baseFeeWei) } +func (msg MsgEthereumTx) EffectiveGasCapWei(baseFeeWei *big.Int) *big.Int { + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil + } + return txData.EffectiveGasFeeCapWei(baseFeeWei) +} + // GetFrom loads the ethereum sender address from the sigcache and returns an // sdk.AccAddress from its bytes func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress { diff --git a/x/evm/tx_data.go b/x/evm/tx_data.go index c3b21a026..5b1a75a78 100644 --- a/x/evm/tx_data.go +++ b/x/evm/tx_data.go @@ -72,6 +72,7 @@ type TxData interface { // // [Alchemy Docs - maxPriorityFeePerGas vs maxFeePerGas]: https://docs.alchemy.com/docs/maxpriorityfeepergas-vs-maxfeepergas. GetGasFeeCapWei() *big.Int + EffectiveGasFeeCapWei(baseFeeWei *big.Int) *big.Int // GetValueWei: amount of ether (wei units) sent in the transaction. GetValueWei() *big.Int diff --git a/x/evm/tx_data_access_list.go b/x/evm/tx_data_access_list.go index fe5a59177..f55828421 100644 --- a/x/evm/tx_data_access_list.go +++ b/x/evm/tx_data_access_list.go @@ -185,6 +185,10 @@ func (tx *AccessListTx) GetGasFeeCapWei() *big.Int { return tx.GetGasPrice() } +func (tx *AccessListTx) EffectiveGasFeeCapWei(baseFeeWei *big.Int) *big.Int { + return BigIntMax(baseFeeWei, tx.GetGasFeeCapWei()) +} + // GetValueWei returns the tx amount. func (tx *AccessListTx) GetValueWei() *big.Int { if tx.Amount == nil { diff --git a/x/evm/tx_data_dynamic_fee.go b/x/evm/tx_data_dynamic_fee.go index 111abba63..694ed7bfb 100644 --- a/x/evm/tx_data_dynamic_fee.go +++ b/x/evm/tx_data_dynamic_fee.go @@ -167,6 +167,10 @@ func (tx *DynamicFeeTx) GetGasFeeCapWei() *big.Int { return tx.GasFeeCap.BigInt() } +func (tx *DynamicFeeTx) EffectiveGasFeeCapWei(baseFeeWei *big.Int) *big.Int { + return BigIntMax(baseFeeWei, tx.GetGasFeeCapWei()) +} + // GetValueWei returns the tx amount. func (tx *DynamicFeeTx) GetValueWei() *big.Int { if tx.Amount == nil { diff --git a/x/evm/tx_data_legacy.go b/x/evm/tx_data_legacy.go index 73c15ffaf..9f334ce97 100644 --- a/x/evm/tx_data_legacy.go +++ b/x/evm/tx_data_legacy.go @@ -104,6 +104,10 @@ func (tx *LegacyTx) GetGasFeeCapWei() *big.Int { return tx.GetGasPrice() } +func (tx *LegacyTx) EffectiveGasFeeCapWei(baseFeeWei *big.Int) *big.Int { + return BigIntMax(baseFeeWei, tx.GetGasFeeCapWei()) +} + // GetValueWei returns the tx amount. func (tx *LegacyTx) GetValueWei() *big.Int { if tx.Amount == nil { From b99631b839521bc1ab0f67e3ca1abe207645bdf0 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 13 Oct 2024 05:17:48 -0500 Subject: [PATCH 6/6] fix e2e tests --- e2e/evm/test/contract_send_nibi.test.ts | 5 +++-- e2e/evm/test/native_transfer.test.ts | 6 ++++-- justfile | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/e2e/evm/test/contract_send_nibi.test.ts b/e2e/evm/test/contract_send_nibi.test.ts index bbcec6459..9ef0e6277 100644 --- a/e2e/evm/test/contract_send_nibi.test.ts +++ b/e2e/evm/test/contract_send_nibi.test.ts @@ -48,9 +48,10 @@ async function testSendNibi( to: receipt.to, from: receipt.from, }) - const deltaFromExpectation = ownerBalanceAfter - expectedOwnerWei - expect(deltaFromExpectation).toBeLessThan(parseEther("0.001")) expect(recipientBalanceAfter).toBe(weiToSend) + const delta = ownerBalanceAfter - expectedOwnerWei + const deltaFromExpectation = delta >= 0 ? delta : -delta + expect(deltaFromExpectation).toBeLessThan(parseEther("0.1")) } describe("Send NIBI via smart contract", () => { diff --git a/e2e/evm/test/native_transfer.test.ts b/e2e/evm/test/native_transfer.test.ts index 4b3c098c2..803dfd43b 100644 --- a/e2e/evm/test/native_transfer.test.ts +++ b/e2e/evm/test/native_transfer.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "@jest/globals" -import { toBigInt } from "ethers" +import { parseEther, toBigInt } from "ethers" import { account, provider } from "./setup" import { alice } from "./utils" @@ -38,6 +38,8 @@ describe("native transfer", () => { txResponse, }) expect(recipientBalanceAfter).toEqual(amountToSend) - expect(senderBalanceAfter).toEqual(expectedSenderWei) + const delta = senderBalanceAfter - expectedSenderWei + const deltaFromExpectation = delta >= 0 ? delta : -delta + expect(deltaFromExpectation).toBeLessThan(parseEther("0.1")) }, 20e3) }) diff --git a/justfile b/justfile index 896265ad9..e1b2aa699 100644 --- a/justfile +++ b/justfile @@ -67,7 +67,7 @@ log-localnet: # Runs the EVM E2E test with logging (logs/e2e.txt) log-e2e: #!/usr/bin/env bash - just test-e2e 2>&1 | tee -a ../../logs/e2e.txt + just test-e2e 2>&1 | tee -a logs/e2e.txt # Runs the EVM E2E tests test-e2e: