Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(evm): gas usage in precompiles: limits, local gas meters #2093

Merged
merged 33 commits into from
Nov 5, 2024

Conversation

onikonychev
Copy link
Contributor

@onikonychev onikonychev commented Oct 25, 2024

Notes

  1. Introduced local gas meters within precompiles. So that, when precompile is executed from another contract, it could have custom gas limit set (part of the parent contract gas limit)

Example:

function callBankSendLocalGas(
        uint256 amount,
        string memory bech32Recipient,
        uint256 customGas
    ) public {
        (bool success,) = FUNTOKEN_PRECOMPILE_ADDRESS.call{gas: customGas}(
            abi.encodeWithSignature(
                "bankSend(address,uint256,string)",
                erc20,
                amount,
                bech32Recipient
            )
        );
        require(success, "Failed to call bankSend with custom gas");
    }
  1. Added parameter gasLimit to CallContractWithInput to limit gas for internal calls related to funtoken.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced foundry support for Nibiru EVM development.
    • Added gas usage limits in precompiles and a validation feature for token creation fees.
    • New contract for local gas settings in FunToken precompile.
    • Enhanced gas management with new constants for ERC20 and Wasm operations.
    • Implemented a new method for handling log events in Ethereum transactions.
  • Bug Fixes

    • Improved ERC20 metadata handling and gas price usage in RefundGas.
    • Enhanced state consistency during precompile execution.
    • Refined error handling for transaction reverts and gas overflow scenarios.
  • Performance Improvements

    • Optimized gas management in contract interactions and execution.
    • Streamlined gas consumption tracking in precompiled contract executions.
    • Improved error reporting for transaction failures.
  • Documentation

    • Updated changelog to reflect recent changes and enhancements.
  • Tests

    • Enhanced test cases for gas management and contract interactions.
    • Introduced new tests for precompile behavior under different gas conditions.
    • Updated tests to reflect changes in method signatures and error handling.

Copy link
Contributor

coderabbitai bot commented Oct 25, 2024

Walkthrough

The changes in this pull request include updates to the CHANGELOG.md to document new features, bug fixes, and refactoring efforts related to the Nibiru EVM. Key modifications involve the introduction of a new contract for local gas management in FunToken precompiles, enhancements in gas limit handling across various components, and updates to several testing suites to incorporate gas management improvements. Additionally, there are several method signature updates and the addition of new methods to facilitate better gas management during contract interactions.

Changes

File Path Change Summary
CHANGELOG.md Added entries for new features, bug fixes, refactoring, performance improvements, and documentation updates related to Nibiru EVM.
src/evm/msgs.go Added method deductCreateFunTokenFee.
src/evm/precompiles.go Updated method signature for gasUsageInPrecompiles.
x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json Introduced new JSON metadata file for TestFunTokenPrecompileLocalGas contract.
x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol Added contract TestFunTokenPrecompileLocalGas with functions callBankSend and callBankSendLocalGas.
x/evm/embeds/embeds.go Added embedded JSON variable testFunTokenPrecompileLocalGasJson and contract declaration SmartContract_TestFunTokenPrecompileLocalGas.
x/evm/embeds/embeds_test.go Added call to embeds.SmartContract_TestFunTokenPrecompileLocalGas.MustLoad() in tests.
x/evm/evmtest/test_deps.go Introduced method ResetGasMeter to reset the gas meter in tests.
x/evm/keeper/erc20.go Added gas limit constants for ERC20 operations and updated methods to utilize these constants.
x/evm/keeper/funtoken_from_coin.go Updated deployERC20ForBankCoin method to include gas limit parameter.
x/evm/keeper/funtoken_from_coin_test.go Modified tests to reset gas meter and include gas limit in contract calls.
x/evm/keeper/funtoken_from_erc20_test.go Added gas limit parameters in tests for mint and bankSend functions.
x/evm/keeper/grpc_query.go Updated method signatures to include new boolean parameter in ApplyEvmMsg calls.
x/evm/keeper/keeper.go Renamed method GetMinGasMultiplier to GetMinGasUsedMultiplier and updated comments.
x/evm/keeper/msg_server.go Added fullRefundLeftoverGas parameter to ApplyEvmMsg method and updated refund logic.
x/evm/precompile/funtoken.go Introduced gas limit constant FunTokenGasLimitBankSend and refined error handling in bankSend.
x/evm/precompile/funtoken_test.go Enhanced test suite structure and added new test for precompile local gas settings.
x/evm/precompile/oracle.go Updated variable handling in Run method and added deferred gas meter reset.
x/evm/precompile/oracle_test.go Introduced OracleGasLimitQuery constant and updated test cases to use it.
x/evm/precompile/precompile.go Added parentGasMeter to OnRunStartResult and introduced HandleOutOfGasPanic function.
x/evm/precompile/test/export.go Added constants for Wasm gas limits and updated test functions to utilize them.
x/evm/precompile/wasm.go Enhanced error handling and gas management in Run method of precompileWasm.
x/evm/precompile/wasm_test.go Added constants for Wasm gas limits and updated test methods accordingly.
x/evm/statedb/journal_test.go Updated test method to include gas limit in contract execution calls.
x/evm/keeper/call_contract.go Introduced methods CallContract and CallContractWithInput for invoking smart contracts.
evm-e2e/.gitignore Added entries to ignore specific directories and files in version control.
x/evm/embeds/artifacts/contracts/TestERC20TransferThenPrecompileSend.sol/TestERC20TransferThenPrecompileSend.json Updated JSON artifact with new bytecode and deployed bytecode.
x/evm/embeds/contracts/TestERC20TransferThenPrecompileSend.sol Modified erc20TransferThenPrecompileSend function for improved error handling.
x/evm/evmmodule/genesis_test.go Updated return values in TestExportInitGenesis method for ERC20 transfers.
x/evm/keeper/erc20_test.go Updated Transfer method calls to capture additional return value.

Possibly related issues

Possibly related PRs

Suggested labels

x: evm

Suggested reviewers

  • Unique-Divine

🐰 In the land where code does grow,
New features sprout, and bugs do go.
Gas limits set, with care they flow,
FunTokens dance, in tests they show.
With every change, our EVM glows! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Oct 26, 2024

Codecov Report

Attention: Patch coverage is 68.95161% with 77 lines in your changes missing coverage. Please review.

Project coverage is 64.75%. Comparing base (1c8df54) to head (8d0e2fb).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
x/evm/keeper/msg_server.go 67.85% 14 Missing and 4 partials ⚠️
x/evm/keeper/call_contract.go 75.71% 13 Missing and 4 partials ⚠️
x/evm/keeper/keeper.go 47.82% 10 Missing and 2 partials ⚠️
x/evm/keeper/grpc_query.go 60.00% 5 Missing and 3 partials ⚠️
x/evm/errors.go 0.00% 6 Missing ⚠️
x/evm/keeper/erc20.go 75.00% 5 Missing ⚠️
eth/rpc/backend/call_tx.go 0.00% 3 Missing ⚠️
x/evm/evmtest/test_deps.go 0.00% 3 Missing ⚠️
x/evm/precompile/funtoken.go 86.95% 2 Missing and 1 partial ⚠️
x/evm/precompile/precompile.go 83.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2093      +/-   ##
==========================================
+ Coverage   64.68%   64.75%   +0.06%     
==========================================
  Files         272      273       +1     
  Lines       21394    21414      +20     
==========================================
+ Hits        13839    13866      +27     
+ Misses       6594     6589       -5     
+ Partials      961      959       -2     
Files with missing lines Coverage Δ
x/evm/embeds/embeds.go 72.41% <100.00%> (+0.98%) ⬆️
x/evm/keeper/funtoken_from_coin.go 78.18% <100.00%> (ø)
x/evm/keeper/gas_fees.go 57.94% <ø> (-5.61%) ⬇️
x/evm/msg.go 62.26% <100.00%> (ø)
x/evm/precompile/oracle.go 54.90% <100.00%> (ø)
x/evm/precompile/wasm.go 62.50% <100.00%> (+1.70%) ⬆️
x/evm/precompile/precompile.go 60.82% <83.33%> (+3.17%) ⬆️
eth/rpc/backend/call_tx.go 55.95% <0.00%> (ø)
x/evm/evmtest/test_deps.go 90.00% <0.00%> (-10.00%) ⬇️
x/evm/precompile/funtoken.go 50.73% <86.95%> (+6.10%) ⬆️
... and 6 more

... and 1 file with indirect coverage changes

@onikonychev onikonychev marked this pull request as ready for review October 28, 2024 17:09
@onikonychev onikonychev requested a review from a team as a code owner October 28, 2024 17:09
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 23

🧹 Outside diff range and nitpick comments (20)
x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol (2)

7-7: Consider adding explicit visibility modifier.

The erc20 state variable should have an explicit visibility modifier for better code clarity.

-    address erc20;
+    address private immutable erc20;

6-47: Consider architectural improvements.

Suggestions for better architecture:

  1. Define an interface for the FunToken precompile
  2. Add events for successful transfers
  3. Consider implementing a more robust error handling mechanism

Example interface:

interface IFunTokenPrecompile {
    function bankSend(
        address token,
        uint256 amount,
        string memory recipient
    ) external returns (bool);
}

Example event:

event BankSendExecuted(
    address indexed token,
    uint256 amount,
    string recipient,
    uint256 gasUsed
);
x/evm/evmtest/test_deps.go (1)

64-67: Add documentation for the ResetGasMeter method.

The implementation looks good, but consider adding a doc comment to explain the method's purpose and when it should be used in tests.

+// ResetGasMeter resets both the transient gas state and the gas meter in the EVM context.
+// This is useful in tests where you need to clear gas usage between operations.
 func (deps TestDeps) ResetGasMeter() {
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 64-66: x/evm/evmtest/test_deps.go#L64-L66
Added lines #L64 - L66 were not covered by tests

x/evm/precompile/oracle_test.go (1)

15-15: Document the rationale for the gas limit value.

Consider adding a comment explaining why 100,000 was chosen as the gas limit for oracle queries. This helps maintainers understand if this value needs adjustment in the future.

x/evm/precompile/oracle.go (1)

Line range hint 41-63: Well-structured gas management implementation.

The implementation of local gas meters in the oracle precompile follows good practices:

  1. Clear separation of gas meter initialization and cleanup
  2. Proper error propagation
  3. Safe gas consumption checks

Consider documenting these gas management patterns in a shared location as they might be useful for other precompiles.

x/evm/embeds/embeds.go (1)

81-86: Consider enhancing the documentation with more specific details.

While the implementation is correct and follows the package patterns, the documentation could be more specific about:

  • The purpose of the local gas limit feature
  • How it differs from regular precompile calls
  • Expected usage scenarios

Example enhancement:

 // SmartContract_TestFunTokenPrecompileLocalGas is a test contract
-// which allows precompile execution with custom local gas set (calling precompile within contract)
+// which demonstrates and tests the execution of precompiles with custom gas limits
+// from within another contract. This enables controlled gas consumption for
+// precompile calls, ensuring they operate within a subset of the parent
+// contract's gas allowance.
x/evm/keeper/erc20.go (1)

16-26: LGTM! Consider enhancing constant documentation.

The gas limits are well-structured and appropriate for their respective operations. The deployment limit provides adequate headroom, query limit is suitable for read operations, and execute limit aligns with typical ERC20 operation costs.

Consider adding references to standard ERC20 operation gas costs in the comments to justify these limits. For example:

 // Erc20GasLimitExecute used for transfer, mint and burn.
-// All must not exceed 200_000
+// Standard ERC20 operations typically consume:
+// - transfer: ~65,000 gas
+// - mint: ~90,000 gas
+// - burn: ~80,000 gas
+// 200,000 limit provides sufficient headroom
 Erc20GasLimitExecute uint64 = 200_000
x/evm/precompile/funtoken_test.go (2)

Line range hint 93-153: Consider adding more assertions for gas consumption.

The test structure looks good and properly validates the basic functionality. However, since this PR focuses on gas management, consider adding assertions to verify:

  1. Gas consumption after each operation
  2. Remaining gas in the gas meter
  3. Gas refunds if applicable

Example assertion:

// Assert gas consumption is within expected range
gasUsed := deps.Ctx.GasMeter().GasConsumed()
s.Assert().Greater(gasUsed, uint64(0))
s.Assert().Less(gasUsed, keeper.Erc20GasLimitQuery)

155-218: Enhance gas limit test coverage.

While the test effectively validates the happy path for local gas usage, consider adding:

  1. Negative test cases:

    • Insufficient gas limit
    • Zero gas limit
    • Gas limit exceeding parent contract's limit
  2. Specific gas consumption assertions:

    • Verify exact gas used by precompile
    • Check remaining gas after operation
    • Validate gas refunds

Example test cases:

s.T().Log("Fail: insufficient local gas")
_, err = deps.EvmKeeper.CallContract(
    deps.Ctx,
    embeds.SmartContract_TestFunTokenPrecompileLocalGas.ABI,
    deps.Sender.EthAddr,
    &contractAddr,
    true,
    precompile.FunTokenGasLimitBankSend,
    "callBankSendLocalGas",
    big.NewInt(1),
    randomAcc.String(),
    big.NewInt(100), // insufficient gas
)
s.Require().ErrorContains(err, "out of gas")
x/evm/precompile/wasm_test.go (1)

21-25: LGTM! Consider enhancing the constant documentation.

The gas limit constants are well-defined and follow good practices. The values are reasonable for test scenarios and the formatting improves readability.

Consider adding a brief comment explaining the rationale behind these specific gas values to help other developers understand the test constraints:

 // rough gas limits for wasm execution - used in tests only
+// WasmGasLimitQuery: 200k gas sufficient for read-only operations
+// WasmGasLimitExecute: 1M gas sufficient for state-modifying operations
 const (
     WasmGasLimitQuery   uint64 = 200_000
     WasmGasLimitExecute uint64 = 1_000_000
 )
x/evm/precompile/test/export.go (1)

24-28: LGTM! Consider enhancing the documentation.

The gas limit constants are well-defined and appropriately scoped for test usage.

Consider adding a brief comment explaining the rationale behind these specific gas values to help other developers understand the chosen limits.

x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json (2)

1-63: Consider adding natspec documentation.

While the contract implementation looks solid, consider adding natspec documentation in the source contract to:

  • Document the gas management behavior
  • Explain the relationship with the bankSend precompile
  • Provide usage examples with gas limits

1-63: Security considerations for gas management.

The implementation allows for custom gas limits but should be used carefully:

  1. Ensure the parent contract has sufficient gas
  2. Consider implementing minimum gas requirements
  3. Add gas estimation helpers

Would you like me to provide implementation examples for these security enhancements?

x/evm/keeper/funtoken_from_erc20_test.go (1)

Line range hint 332-337: Consider enhancing gas consumption verification

While the error handling for gas-related issues is comprehensive, consider enhancing the test coverage by:

  1. Capturing and verifying the exact gas consumption before the error occurs
  2. Adding assertions to verify that the gas consumption is within expected ranges
  3. Testing edge cases around the gas limits

This would provide more precise validation of the gas management implementation.

Example enhancement for the malicious transfer test:

 	s.T().Log("send erc20 tokens to cosmos")
+	initialGas := deps.Ctx.GasMeter().GasConsumed()
 	_, err = deps.EvmKeeper.CallContract(
 		deps.Ctx,
 		embeds.SmartContract_FunToken.ABI,
 		deps.Sender.EthAddr,
 		&precompile.PrecompileAddr_FunToken,
 		true,
 		precompile.FunTokenGasLimitBankSend,
 		"bankSend",
 		deployResp.ContractAddr,
 		big.NewInt(1),
 		randomAcc.String(),
 	)
+	gasUsed := deps.Ctx.GasMeter().GasConsumed() - initialGas
+	s.Require().Greater(gasUsed, precompile.FunTokenGasLimitBankSend, "gas consumption should exceed limit")
 	s.Require().ErrorContains(err, "gas required exceeds allowance")

Also applies to: 384-386

x/evm/keeper/grpc_query.go (1)

803-803: LGTM: Consider adding documentation.

The false parameter is correctly added for transaction message tracing. Consider adding a comment explaining the purpose of this parameter for better maintainability.

-	res, _, err := k.ApplyEvmMsg(ctx, msg, tracer, commitMessage, cfg, txConfig, false)
+	// Pass false to prevent committing state changes during tracing
+	res, _, err := k.ApplyEvmMsg(ctx, msg, tracer, commitMessage, cfg, txConfig, false)
CHANGELOG.md (1)

72-72: Consider expanding the changelog entry to better reflect the changes.

The current entry for PR #2093 could be expanded to better document the significant changes introduced, such as:

  • Addition of local gas meters for precompile execution
  • Support for custom gas limits in precompile calls
  • Relocation of CallContractWithInput method
  • Addition of gasLimit parameter
  • Reorganization of funtoken methods
-- [#2093](https://github.com/NibiruChain/nibiru/pull/2093) - feat(evm): gas usage in precompiles: limits, local gas meters
+- [#2093](https://github.com/NibiruChain/nibiru/pull/2093) - feat(evm): gas usage in precompiles: limits, local gas meters. Introduces local gas meters for precompile execution, allowing custom gas limits for precompile calls. Relocates CallContractWithInput method from ERC20 module to msg_server.go, adds gasLimit parameter, and reorganizes funtoken methods.
x/evm/keeper/funtoken_from_coin.go (1)

128-133: Ensure Atomicity in Coin Transfer and Error Handling

When transferring coins from the sender to the module account, ensure that the operation is atomic to prevent partial transfers in case of failures. The current implementation seems appropriate, but consider reviewing transaction atomicity for robustness.

x/evm/precompile/funtoken.go (1)

31-41: Clarify Gas Limit Calculation in Comments

The comments provide gas estimates for each step, totaling approximately 325,000 gas:

  • Step 1: Up to 200,000 gas
  • Step 2: ~60,000 gas
  • Step 3: ~65,000 gas
  • Total: ~325,000 gas

However, FunTokenGasLimitBankSend is set to 400,000 gas. Consider updating the comments to explain the additional 75,000 gas (perhaps accounting for overhead or gas discrepancies) or adjust the constant to better reflect the estimated total.

x/evm/keeper/funtoken_from_erc20.go (1)

211-216: Add detailed function parameter documentation

To enhance readability and maintainability, consider adding GoDoc comments for each parameter of the convertCoinNativeERC20 function. This will help other developers understand the purpose and expected values of each parameter.

x/evm/keeper/msg_server.go (1)

252-255: Clarify Documentation for New Parameter fullRefundLeftoverGas

The ApplyEvmMsg function now includes the boolean parameter fullRefundLeftoverGas, which affects gas refund logic. Ensure that the function's documentation clearly explains the purpose and impact of this parameter. Providing detailed comments or examples can help other developers understand its intended use and avoid misuse.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3aac937 and f3e3b87.

📒 Files selected for processing (23)
  • CHANGELOG.md (1 hunks)
  • x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json (1 hunks)
  • x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol (1 hunks)
  • x/evm/embeds/embeds.go (3 hunks)
  • x/evm/embeds/embeds_test.go (1 hunks)
  • x/evm/evmtest/test_deps.go (1 hunks)
  • x/evm/keeper/erc20.go (7 hunks)
  • x/evm/keeper/funtoken_from_coin.go (2 hunks)
  • x/evm/keeper/funtoken_from_coin_test.go (2 hunks)
  • x/evm/keeper/funtoken_from_erc20.go (2 hunks)
  • x/evm/keeper/funtoken_from_erc20_test.go (5 hunks)
  • x/evm/keeper/grpc_query.go (4 hunks)
  • x/evm/keeper/keeper.go (2 hunks)
  • x/evm/keeper/msg_server.go (5 hunks)
  • x/evm/precompile/funtoken.go (3 hunks)
  • x/evm/precompile/funtoken_test.go (5 hunks)
  • x/evm/precompile/oracle.go (2 hunks)
  • x/evm/precompile/oracle_test.go (2 hunks)
  • x/evm/precompile/precompile.go (4 hunks)
  • x/evm/precompile/test/export.go (4 hunks)
  • x/evm/precompile/wasm.go (2 hunks)
  • x/evm/precompile/wasm_test.go (5 hunks)
  • x/evm/statedb/journal_test.go (2 hunks)
🧰 Additional context used
🪛 GitHub Check: codecov/patch
x/evm/evmtest/test_deps.go

[warning] 64-66: x/evm/evmtest/test_deps.go#L64-L66
Added lines #L64 - L66 were not covered by tests

x/evm/keeper/funtoken_from_coin.go

[warning] 104-105: x/evm/keeper/funtoken_from_coin.go#L104-L105
Added lines #L104 - L105 were not covered by tests


[warning] 107-108: x/evm/keeper/funtoken_from_coin.go#L107-L108
Added lines #L107 - L108 were not covered by tests


[warning] 149-150: x/evm/keeper/funtoken_from_coin.go#L149-L150
Added lines #L149 - L150 were not covered by tests


[warning] 152-154: x/evm/keeper/funtoken_from_coin.go#L152-L154
Added lines #L152 - L154 were not covered by tests

x/evm/keeper/funtoken_from_erc20.go

[warning] 221-222: x/evm/keeper/funtoken_from_erc20.go#L221-L222
Added lines #L221 - L222 were not covered by tests


[warning] 224-225: x/evm/keeper/funtoken_from_erc20.go#L224-L225
Added lines #L224 - L225 were not covered by tests


[warning] 245-246: x/evm/keeper/funtoken_from_erc20.go#L245-L246
Added lines #L245 - L246 were not covered by tests


[warning] 248-249: x/evm/keeper/funtoken_from_erc20.go#L248-L249
Added lines #L248 - L249 were not covered by tests


[warning] 251-252: x/evm/keeper/funtoken_from_erc20.go#L251-L252
Added lines #L251 - L252 were not covered by tests


[warning] 263-264: x/evm/keeper/funtoken_from_erc20.go#L263-L264
Added lines #L263 - L264 were not covered by tests


[warning] 266-267: x/evm/keeper/funtoken_from_erc20.go#L266-L267
Added lines #L266 - L267 were not covered by tests


[warning] 272-273: x/evm/keeper/funtoken_from_erc20.go#L272-L273
Added lines #L272 - L273 were not covered by tests


[warning] 275-276: x/evm/keeper/funtoken_from_erc20.go#L275-L276
Added lines #L275 - L276 were not covered by tests


[warning] 280-281: x/evm/keeper/funtoken_from_erc20.go#L280-L281
Added lines #L280 - L281 were not covered by tests


[warning] 286-287: x/evm/keeper/funtoken_from_erc20.go#L286-L287
Added lines #L286 - L287 were not covered by tests

x/evm/keeper/msg_server.go

[warning] 348-349: x/evm/keeper/msg_server.go#L348-L349
Added lines #L348 - L349 were not covered by tests


[warning] 591-592: x/evm/keeper/msg_server.go#L591-L592
Added lines #L591 - L592 were not covered by tests


[warning] 650-652: x/evm/keeper/msg_server.go#L650-L652
Added lines #L650 - L652 were not covered by tests


[warning] 665-669: x/evm/keeper/msg_server.go#L665-L669
Added lines #L665 - L669 were not covered by tests


[warning] 688-690: x/evm/keeper/msg_server.go#L688-L690
Added lines #L688 - L690 were not covered by tests


[warning] 695-696: x/evm/keeper/msg_server.go#L695-L696
Added lines #L695 - L696 were not covered by tests

x/evm/precompile/funtoken.go

[warning] 94-95: x/evm/precompile/funtoken.go#L94-L95
Added lines #L94 - L95 were not covered by tests

x/evm/precompile/oracle.go

[warning] 61-62: x/evm/precompile/oracle.go#L61-L62
Added lines #L61 - L62 were not covered by tests

x/evm/precompile/precompile.go

[warning] 238-239: x/evm/precompile/precompile.go#L238-L239
Added lines #L238 - L239 were not covered by tests

x/evm/precompile/wasm.go

[warning] 72-73: x/evm/precompile/wasm.go#L72-L73
Added lines #L72 - L73 were not covered by tests

🔇 Additional comments (51)
x/evm/embeds/embeds_test.go (1)

19-19: LGTM! The test addition aligns with PR objectives.

The new test case follows the established pattern and verifies the loading of the TestFunTokenPrecompileLocalGas contract, which is essential for testing the new local gas meter functionality.

Let's verify the contract's existence:

✅ Verification successful

Contract verification successful - both source and artifact files exist

The verification confirms that both required files are present in the expected locations:

  • Source: x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol
  • Artifact: x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the TestFunTokenPrecompileLocalGas contract exists
# Expected: Find the contract file and its corresponding JSON artifact

# Test 1: Find the contract file
fd "TestFunTokenPrecompileLocalGas.sol" --type f

# Test 2: Find the contract's JSON artifact
fd "TestFunTokenPrecompileLocalGas.json" --type f

Length of output: 260

x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol (1)

4-4: Verify the imported constant usage.

The contract uses FUNTOKEN_PRECOMPILE_ADDRESS but it's not clear where this constant is defined.

✅ Verification successful

Let me gather more information about the constant definition.


Import is correctly used and constant is properly defined

The constant FUNTOKEN_PRECOMPILE_ADDRESS is defined in FunToken.sol as 0x0000000000000000000000000000000000000800 and is properly used in TestFunTokenPrecompileLocalGas.sol for making precompile calls. The import statement is necessary and valid.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for FUNTOKEN_PRECOMPILE_ADDRESS definition
rg -l "FUNTOKEN_PRECOMPILE_ADDRESS"

# Search for the constant's value in FunToken.sol
ast-grep --pattern 'constant FUNTOKEN_PRECOMPILE_ADDRESS = $_'

Length of output: 194


Script:

#!/bin/bash
# Show the content around FUNTOKEN_PRECOMPILE_ADDRESS in both files
rg -B2 -A2 "FUNTOKEN_PRECOMPILE_ADDRESS" x/evm/embeds/contracts/FunToken.sol x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol

Length of output: 1484

x/evm/evmtest/test_deps.go (1)

64-67: Ensure test coverage for the new ResetGasMeter method.

While this method is part of test utilities and might be indirectly tested through its usage in funtoken tests, consider adding direct unit tests to verify its behavior.

Would you like me to help create unit tests for this method?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 64-66: x/evm/evmtest/test_deps.go#L64-L66
Added lines #L64 - L66 were not covered by tests

x/evm/precompile/oracle_test.go (1)

64-69: Verify the purpose of the false parameter.

The boolean parameter (line 67) seems to be related to gas limit usage. Please verify its purpose and consider adding a comment explaining what this boolean controls, as it's not immediately clear from the context.

✅ Verification successful

From the search results, I found the documentation of CallContractWithInput in x/evm/keeper/msg_server.go which shows that the boolean parameter is named commit and is used to determine whether the contract call should be committed or simulated. Looking at the usage patterns across the codebase:

  1. For query operations (like in oracle_test.go), commit is set to false
  2. For state-changing operations (like in other tests), commit is set to true

The false value in the oracle test is correct because it's performing a query operation (queryExchangeRate) which doesn't modify state.

The false parameter is correctly used for this query operation.

The boolean parameter controls whether the contract call should commit changes (true) or just simulate/query (false). In this case, since it's a query to get exchange rate data, using false is the appropriate choice.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the CallContractWithInput definition to understand the boolean parameter
ast-grep --pattern 'func $_ CallContractWithInput($_, $_, $_, $useGasLimit bool, $_, $_)'

Length of output: 91


Script:

#!/bin/bash
# Let's try a broader search for CallContractWithInput function definition
rg -A 5 "CallContractWithInput" 

# Also search for any comments or documentation about this function
rg -B 2 -A 5 "CallContractWithInput"

Length of output: 13478

x/evm/precompile/oracle.go (3)

41-45: LGTM! Clear variable naming improvement.

The rename from 'res' to 'start' better reflects the initialization nature of the OnRunStart function.


47-48: Excellent gas meter cleanup implementation!

The deferred reset of the gas meter is a crucial safety feature that ensures:

  1. Proper cleanup of gas meter state
  2. Graceful handling of "out of gas" scenarios
  3. Consistent gas tracking across precompile executions

58-62: Add tests and documentation for gas consumption check.

This critical gas consumption check needs:

  1. Test coverage to verify proper handling of out-of-gas scenarios
  2. A comment explaining the purpose and importance of this check

Would you like me to help:

  1. Generate test cases for the gas consumption check?
  2. Draft documentation for this security-critical feature?
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 61-62: x/evm/precompile/oracle.go#L61-L62
Added lines #L61 - L62 were not covered by tests

x/evm/embeds/embeds.go (3)

32-33: LGTM! Embedded JSON declaration follows established patterns.

The new embedded JSON variable follows the package's conventions for naming and file structure.


97-97: LGTM! Contract loading follows established patterns.

The initialization is correctly implemented using MustLoad(), maintaining consistency with other contract loading.


32-33: Verify the contract's integration and test coverage.

Let's ensure the contract is properly integrated and tested:

Also applies to: 81-86

✅ Verification successful

Let me gather more information about the test files to better understand the integration.


Let me check the actual Solidity contract implementation to complete the verification.


Based on the comprehensive verification results, I can now provide the final response:

Contract is properly integrated and well-tested ✅

The verification confirms:

  • The Solidity contract exists and implements gas-specific test scenarios for the FunToken precompile
  • The contract is properly used in test files:
    • x/evm/precompile/funtoken_test.go: Tests both default and custom gas scenarios
    • x/evm/embeds/embeds_test.go: Verifies contract loading
  • The implementation aligns with its intended purpose of testing gas limits in precompiles
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify contract integration and test coverage

# Test 1: Check if the JSON file exists
echo "Checking for contract JSON file..."
fd -t f "TestFunTokenPrecompileLocalGas.json" artifacts/

# Test 2: Look for test files using this contract
echo "Checking for test files using this contract..."
rg -l "TestFunTokenPrecompileLocalGas" -g "**/*_test.go"

# Test 3: Check for actual contract usage
echo "Checking for contract usage in codebase..."
rg "SmartContract_TestFunTokenPrecompileLocalGas" -g "!**/embeds.go"

Length of output: 994


Script:

#!/bin/bash
# Check the test implementations to understand how the contract is used
echo "Checking funtoken_test.go implementation..."
rg -A 5 -B 5 "TestFunTokenPrecompileLocalGas" x/evm/precompile/funtoken_test.go

echo -e "\nChecking embeds_test.go implementation..."
rg -A 5 -B 5 "TestFunTokenPrecompileLocalGas" x/evm/embeds/embeds_test.go

# Check if there's a corresponding Solidity contract
echo -e "\nLooking for the Solidity contract..."
fd -t f "TestFunTokenPrecompileLocalGas.sol"

Length of output: 1826


Script:

#!/bin/bash
# Check the Solidity contract implementation
echo "Checking Solidity contract implementation..."
cat x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol

# Verify if the contract is properly loaded in embeds.go
echo -e "\nChecking contract loading in embeds.go..."
rg -A 5 "var SmartContract_TestFunTokenPrecompileLocalGas" x/evm/embeds/embeds.go

Length of output: 1748

x/evm/keeper/keeper.go (2)

7-7: LGTM: Import change looks correct.

The import of cosmossdk.io/math is appropriate as it's used by the GetMinGasUsedMultiplier method.


112-116: LGTM: Method rename and documentation improvements.

The rename to GetMinGasUsedMultiplier better reflects the method's purpose, and the documentation clearly explains how the gas limit and multiplier interact.

x/evm/statedb/journal_test.go (2)

12-13: LGTM: Import added for accessing gas limit constants.

The keeper package import is correctly added to support the gas limit parameter changes.


70-75: Verify gas limit appropriateness for test scenarios.

The addition of keeper.Erc20GasLimitExecute as the gas limit parameter aligns with the PR objectives. However, we should ensure this limit is appropriate for the test scenario and consistent across similar test cases.

Let's verify the consistency of gas limit usage across test files:

✅ Verification successful

Let me analyze the results and generate a final response based on the findings.

Gas limit parameter is consistently used across the codebase

The verification shows that CallContractWithInput is properly used with appropriate gas limits across the codebase:

  • ERC20 operations use Erc20GasLimitExecute in keeper operations
  • Test files correctly use the gas limit parameter:
    • journal_test.go uses Erc20GasLimitExecute for ERC20 operations
    • funtoken_test.go uses Erc20GasLimitQuery for queries
    • Precompile tests (oracle_test.go, wasm_test.go) have their own gas limit configurations

The gas limit parameter addition is appropriate for the test scenario and maintains consistency with the production code patterns.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other test files that might need similar gas limit updates
# and verify the consistency of CallContractWithInput usage.

# Search for other test files using CallContractWithInput
echo "Files containing CallContractWithInput calls that might need gas limit updates:"
rg -l "CallContractWithInput" --type go --type-add 'go:*.go' | grep "_test.go"

# Check the actual usage patterns
echo -e "\nUsage patterns of CallContractWithInput:"
rg -A 5 "CallContractWithInput\(" --type go

Length of output: 6043

x/evm/keeper/erc20.go (6)

66-66: LGTM! Gas limit properly applied to mint operation.

The addition of Erc20GasLimitExecute ensures controlled gas consumption for minting operations.


88-88: LGTM! Gas limit properly applied to transfer operation.

The addition of Erc20GasLimitExecute ensures controlled gas consumption for transfer operations.


128-128: LGTM! Gas limit properly applied to burn operation.

The addition of Erc20GasLimitExecute ensures controlled gas consumption for burn operations.


157-163: LGTM! Query gas limit properly applied to string loading operations.

The addition of Erc20GasLimitQuery is appropriate for these read-only operations.


189-191: LGTM! Query gas limit properly applied to uint8 loading operations.

The addition of Erc20GasLimitQuery is appropriate for these read-only operations.


220-220: LGTM! Query gas limit properly applied to BigInt loading operations.

The addition of Erc20GasLimitQuery is appropriate for these read-only operations.

x/evm/precompile/funtoken_test.go (2)

11-12: LGTM! Well-structured test suite modifications.

The addition of deps and funtoken fields to FuntokenSuite improves test organization and follows good practices for dependency injection.

Also applies to: 30-32


34-40: LGTM! Clean and well-documented test setup.

The SetupSuite implementation properly initializes test dependencies and includes helpful logging.

x/evm/precompile/wasm_test.go (3)

62-67: LGTM! Gas limit properly applied to denom creation call.

The gas limit is appropriately set for the contract execution, and error handling is in place.


333-338: LGTM! Consistent gas limit usage in error test cases.

The execution gas limit is consistently applied even in error test cases, which is a good practice for thorough testing.


155-163: LGTM! Verify gas meter reset effectiveness.

The gas meter reset and query gas limit are properly implemented. The lower gas limit for queries is appropriate for read-only operations.

Let's verify that the gas meter reset is working as expected:

✅ Verification successful

Gas meter reset is consistently used before gas-sensitive operations

The verification shows that ResetGasMeter() is consistently used before EVM contract calls and other gas-sensitive operations across test files. The implementation in evmtest/test_deps.go properly resets both transient and regular gas meters, ensuring accurate gas measurements in tests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if ResetGasMeter is consistently used before gas-sensitive operations
# across the codebase to ensure accurate gas measurements in tests.

rg -B 2 -A 2 'ResetGasMeter\(\)' --type go

Length of output: 2997

x/evm/keeper/funtoken_from_coin_test.go (2)

260-261: LGTM: Proper gas meter reset before conversion.

The addition of ResetGasMeter() ensures accurate gas measurement for the ERC-20 to bank coin conversion operation by starting with a clean gas state.


269-269: LGTM: Gas limit enforcement for bankSend operation.

The addition of precompile.FunTokenGasLimitBankSend implements proper gas management for the bankSend operation, aligning with the PR's objective of introducing local gas meters in precompiles.

Let's verify the gas limit value is appropriate:

Also applies to: 297-297

✅ Verification successful

Let me gather more context about the gas limit usage in the code.


Gas limit value for bankSend is appropriately set

The FunTokenGasLimitBankSend value of 400,000 gas is well-justified based on the code comments and comparison with other gas limits in the codebase:

  • It accounts for ~65,000 gas for bank send operation
  • Includes buffer for additional operations (mint/burn ~60,000 gas each)
  • Aligns proportionally with other precompile gas limits (e.g., Erc20GasLimitExecute: 200,000, WasmGasLimitQuery: 200,000)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the FunTokenGasLimitBankSend constant value and its usage

# Check the constant definition
rg -A 1 "FunTokenGasLimitBankSend.*=.*" 

# Check all usages of this constant
rg "FunTokenGasLimitBankSend"

Length of output: 1014


Script:

#!/bin/bash
# Get the implementation details around FunTokenGasLimitBankSend
ast-grep --pattern 'const FunTokenGasLimitBankSend = $_'

# Get more context around the constant definition and its comments
rg -B 3 -A 3 "FunTokenGasLimitBankSend.*=.*"

# Check if there are any other gas limits defined for comparison
rg "GasLimit.*=.*\d+"

Length of output: 2217

x/evm/precompile/test/export.go (2)

80-85: LGTM! Gas limit properly applied to contract instantiation.

The WasmGasLimitInstantiate constant is correctly used in the CallContractWithInput method.


326-334: Consider scaling gas limit with message count.

While the gas management is generally good with the reset and appropriate limit, the gas limit doesn't scale with the number of messages being executed.

Consider adjusting the gas limit based on the number of messages:

-		WasmGasLimitExecute,
+		WasmGasLimitExecute * uint64(times),

Let's verify if there are any existing tests that might fail with multiple messages:

x/evm/precompile/wasm.go (2)

69-73: ⚠️ Potential issue

Add test coverage for gas consumption checks.

The gas consumption check logic is correct, but lacks test coverage according to static analysis. This is critical functionality that should be thoroughly tested.

Test cases should cover:

  1. Normal case: Contract has sufficient gas
  2. Edge case: Contract runs out of gas
  3. Integration with parent gas meter

Let's verify existing gas-related test coverage:

#!/bin/bash
# Search for gas-related test cases in precompile tests
rg -g "**/*_test.go" -B 5 -A 5 "UseGas|GasConsumed|ErrOutOfGas" x/evm/precompile/

Would you like me to help generate comprehensive test cases for this functionality?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 72-73: x/evm/precompile/wasm.go#L72-L73
Added lines #L72 - L73 were not covered by tests


45-46: LGTM: Gas meter reset implementation looks correct.

The deferred gas meter reset ensures proper cleanup after precompile execution and handles "out of gas" errors gracefully.

Let's verify the ReturnToParentGasMeter implementation:

✅ Verification successful

Gas meter reset implementation is correctly implemented and used

The verification confirms that ReturnToParentGasMeter is properly implemented in x/evm/precompile/precompile.go and correctly used across multiple precompiles. The implementation:

  • Resets the context gas meter back to parent after precompile execution
  • Properly handles out of gas panics by catching storetypes.ErrorOutOfGas
  • Correctly updates the contract's gas usage
  • Is consistently used in all precompile implementations (wasm.go, funtoken.go, oracle.go)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for ReturnToParentGasMeter implementation and usages
rg -A 5 "ReturnToParentGasMeter"

Length of output: 83


Script:

#!/bin/bash
# Let's try a broader search for gas meter related functions and their implementations
rg -A 10 "func.*GasMeter|ReturnToParentGasMeter" 

# Also search for the specific file content
cat x/evm/precompile/wasm.go

Length of output: 21827

x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json (2)

5-57: LGTM: Contract interface properly implements gas management requirements.

The ABI definition correctly implements:

  • Constructor with ERC20 address parameter
  • Base function callBankSend for standard calls
  • Extended function callBankSendLocalGas with custom gas parameter

59-60: Verify the bytecode's gas management implementation.

The bytecode includes proper error handling for failed calls and uses the correct precompile interaction pattern. However, let's verify the gas forwarding implementation in the source contract.

✅ Verification successful

Based on the source code verification, I can now generate the final response:

Gas management implementation is correctly implemented

The bytecode correctly reflects the source contract's gas management implementation where:

  • callBankSend() forwards all available gas (default behavior)
  • callBankSendLocalGas() allows custom gas limit via the gas parameter
  • Both functions include proper error handling with require statements
  • No other hardcoded gas values were found in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the source contract to verify gas forwarding implementation
fd -t f "TestFunTokenPrecompileLocalGas.sol" | xargs cat

# Verify no hardcoded gas values in other precompile calls
rg -g "*.sol" "gas:" -A 5

Length of output: 2077

x/evm/keeper/funtoken_from_erc20_test.go (2)

205-205: LGTM: Consistent gas limit implementation

The gas limits are appropriately set for different operations:

  • Erc20GasLimitExecute for ERC20 mint operations
  • FunTokenGasLimitBankSend for bank send operations

This aligns well with the PR's objective of enhancing gas management in precompiles.

Also applies to: 223-223, 247-247, 379-379


214-215: LGTM: Strategic gas meter resets

Gas meters are appropriately reset before major operations to ensure accurate gas measurement in each test case. The placement is consistent and helps isolate gas consumption for individual operations.

Also applies to: 238-239, 256-257, 370-371

x/evm/keeper/grpc_query.go (3)

287-287: LGTM: Consistent with non-committing behavior.

The addition of false parameter aligns with the comment above about not committing StateDB.


425-425: LGTM: Appropriate for gas estimation.

The false parameter is correctly added to maintain the non-committing nature of gas estimation.


521-521: LGTM: Suitable for transaction tracing.

The false parameter is correctly added to maintain the non-committing nature of transaction tracing.

CHANGELOG.md (1)

Line range hint 1-1338: LGTM! Well-structured changelog following best practices.

The changelog is well-organized and follows the Keep a Changelog format consistently. It effectively documents changes with:

  • Clear sections for different types of changes
  • Consistent PR link formatting
  • Chronological ordering
  • Good use of markdown for readability
x/evm/keeper/funtoken_from_coin.go (5)

4-4: Approved: Proper Import of "context" Package

The import of the "context" package is necessary for using context.Context in the new method ConvertCoinToEvm.


96-117: Review Error Handling in ConvertCoinToEvm Method

The method ConvertCoinToEvm properly handles various error cases such as missing or multiple FunToken mappings. Ensure that all possible error paths are adequately tested.

Would you like help in identifying any untested error paths within this method?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 104-105: x/evm/keeper/funtoken_from_coin.go#L104-L105
Added lines #L104 - L105 were not covered by tests


[warning] 107-108: x/evm/keeper/funtoken_from_coin.go#L107-L108
Added lines #L107 - L108 were not covered by tests


156-160: Approved: Event Emission After Successful Conversion

Emitting the EventConvertCoinToEvm event after a successful conversion is good practice for transparency and auditing.


83-83: Verify the Use of Erc20GasLimitDeploy in Contract Deployment

Ensure that the Erc20GasLimitDeploy parameter is correctly defined and passed to the deployERC20ForBankCoin function. This parameter controls the gas limit for contract deployment and should be consistently used across the codebase.

Run the following script to confirm that Erc20GasLimitDeploy is appropriately defined and used:

#!/bin/bash
# Description: Verify usage of Erc20GasLimitDeploy in the codebase.

# Test: Search for the definition and usage of Erc20GasLimitDeploy.
# Expect: Erc20GasLimitDeploy is defined and used where necessary.

rg 'Erc20GasLimitDeploy'

143-143: Confirm Definition of Erc20GasLimitExecute

The variable Erc20GasLimitExecute used in the CallContract function should be defined and set appropriately. Verify that it holds the correct gas limit value for executing contracts.

Run the following script to check the definition and usage of Erc20GasLimitExecute:

✅ Verification successful

Based on the search results, I can generate the final response as we have found clear evidence of the definition and usage of Erc20GasLimitExecute.

Erc20GasLimitExecute is properly defined with appropriate gas limit

The constant is well-defined in x/evm/keeper/erc20.go with a value of 200,000 gas units and is documented as being used for transfer, mint, and burn operations. This is a reasonable gas limit for ERC20 operations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify definition and usage of Erc20GasLimitExecute.

# Test: Search for the definition and ensure it's correctly assigned.
# Expect: Erc20GasLimitExecute is defined with an appropriate gas limit.

rg 'Erc20GasLimitExecute'

Length of output: 725

x/evm/precompile/precompile.go (2)

151-152: Looks good: Addition of parentGasMeter field

The inclusion of parentGasMeter in the OnRunStartResult struct is appropriate for managing gas meters during precompile execution.


199-205: Verify that ReturnToParentGasMeter is properly invoked

After switching to a local gas meter within OnRunStart, please ensure that ReturnToParentGasMeter is called appropriately to restore the parent gas meter after execution or in case of errors. This is crucial for maintaining accurate gas accounting.

x/evm/precompile/funtoken.go (1)

74-76: Proper Handling of Gas Meter Reset

The deferred call to ReturnToParentGasMeter correctly ensures that the gas meter is reset to the parent gas meter after precompile execution and gracefully handles "out of gas" errors. This implementation enhances the reliability of gas management within the precompile.

x/evm/keeper/funtoken_from_erc20.go (3)

296-296: Ensure consistent return values on errors

Verify that all error paths return nil for the response to maintain consistency and prevent potential nil pointer dereferences.

Please confirm that in all error scenarios, the function returns nil for the *evm.MsgConvertCoinToEvmResponse to ensure consistency.


245-249: 🛠️ Refactor suggestion

Simplify EVM module balance error handling

Similar to the previous comment, consider simplifying the error handling for evmModuleBalance to improve code clarity.

Suggested change:

evmModuleBalance, err := k.ERC20().BalanceOf(
    erc20Addr,
    evm.EVM_MODULE_ADDRESS,
    ctx,
)
if err != nil {
    return nil, errors.Wrap(err, "failed to retrieve EVM module balance")
}
- if evmModuleBalance == nil {
-     return nil, fmt.Errorf("failed to retrieve balance, balance is nil")
- }

Likely invalid or redundant comment.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 245-246: x/evm/keeper/funtoken_from_erc20.go#L245-L246
Added lines #L245 - L246 were not covered by tests


[warning] 248-249: x/evm/keeper/funtoken_from_erc20.go#L248-L249
Added lines #L248 - L249 were not covered by tests


270-276: 🛠️ Refactor suggestion

Simplify recipient balance after transfer error handling

Consistent with prior suggestions, streamline the error checks for recipientBalanceAfter.

Suggested change:

recipientBalanceAfter, err := k.ERC20().BalanceOf(erc20Addr, recipient, ctx)
if err != nil {
    return nil, errors.Wrap(err, "failed to retrieve recipient balance after transfer")
}
- if recipientBalanceAfter == nil {
-     return nil, fmt.Errorf("failed to retrieve balance, balance is nil")
- }

Likely invalid or redundant comment.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 272-273: x/evm/keeper/funtoken_from_erc20.go#L272-L273
Added lines #L272 - L273 were not covered by tests


[warning] 275-276: x/evm/keeper/funtoken_from_erc20.go#L275-L276
Added lines #L275 - L276 were not covered by tests

x/evm/keeper/msg_server.go (1)

66-66: Ensure Consistent Usage of New Parameter in ApplyEvmMsg

At line 66, the ApplyEvmMsg function is called with the new parameter false. Please verify that all other invocations of ApplyEvmMsg throughout the codebase have been updated to include the new fullRefundLeftoverGas parameter to maintain consistency and prevent potential issues.

You can run the following script to identify all usages of ApplyEvmMsg and check for correct parameter usage:

✅ Verification successful

Based on the rg search results, I can generate the final response as all instances of ApplyEvmMsg calls are visible with their parameters.

All ApplyEvmMsg Calls Are Consistent with New Parameter

All invocations of ApplyEvmMsg throughout the codebase have been properly updated to include the new fullRefundLeftoverGas parameter:

  • x/evm/keeper/msg_server.go:66: false for regular EVM transactions
  • x/evm/keeper/msg_server.go:144: true for internal calls
  • x/evm/keeper/grpc_query.go:52: false for query operations
  • x/evm/keeper/grpc_query.go:108: false for estimation
  • x/evm/keeper/grpc_query.go:143: false for trace operations
  • x/evm/keeper/grpc_query.go:171: false for raw call operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for all calls to ApplyEvmMsg and display the surrounding lines.

# Expectation: All calls should include the new parameter.

rg 'ApplyEvmMsg\(' -A 3 -B 3

Length of output: 3408

x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol Outdated Show resolved Hide resolved
x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol Outdated Show resolved Hide resolved
x/evm/keeper/keeper.go Show resolved Hide resolved
Comment on lines 200 to 205
deps.Ctx,
deps.Sender.EthAddr,
&precompile.PrecompileAddr_Wasm,
true,
input,
WasmGasLimitInstantiate,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider using a separate gas limit constant for queries.

Currently using WasmGasLimitInstantiate for a query operation, which is excessive as queries typically consume less gas than contract instantiation.

Consider introducing a new constant like WasmGasLimitQuery with a lower value appropriate for query operations:

 const (
 	WasmGasLimitInstantiate uint64 = 1_000_000
 	WasmGasLimitExecute     uint64 = 10_000_000
+	WasmGasLimitQuery       uint64 = 100_000
 )

Then update the query operation:

-		WasmGasLimitInstantiate,
+		WasmGasLimitQuery,

Committable suggestion was skipped due to low confidence.

Comment on lines 591 to 592
return nil, fmt.Errorf("failed to pack ABI args: %w", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add Test Coverage for ABI Packing Failure

Lines 591-592 handle errors that may occur during ABI argument packing. Consider adding test cases that simulate a packing failure to verify that the error is correctly caught and handled, ensuring robustness in contract interactions.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 591-592: x/evm/keeper/msg_server.go#L591-L592
Added lines #L591 - L592 were not covered by tests

Comment on lines 650 to 652
err = errors.Wrapf(err, "failed to load EVM config")
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add Test Coverage for EVM Config Loading Failure

The error handling at lines 650-652 addresses failures in loading the EVM configuration. Adding unit tests that simulate this failure scenario can help ensure that the system responds appropriately when such an error occurs.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 650-652: x/evm/keeper/msg_server.go#L650-L652
Added lines #L650 - L652 were not covered by tests

Comment on lines 665 to 669
// We don't know the actual gas used, so consuming the gas limit
k.ResetGasMeterAndConsumeGas(ctx, gasLimit)
err = errors.Wrap(err, "failed to apply ethereum core message")
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add Test Coverage for EVM Message Application Failure

Lines 665-669 deal with failures when applying the EVM message. Implementing tests to cover this failure path will help validate that the system handles such errors gracefully and that the correct amount of gas is consumed.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 665-669: x/evm/keeper/msg_server.go#L665-L669
Added lines #L665 - L669 were not covered by tests

Comment on lines 688 to 690
k.ResetGasMeterAndConsumeGas(ctx, ctx.GasMeter().Limit())
return nil, nil, errors.Wrap(err, "error adding transient gas used to block")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add Test Coverage for Block Gas Usage Update Failure

At lines 688-690, there's error handling for failures in updating the block's gas usage. It's important to include tests that cover this scenario to ensure that any issues in gas accounting are detected and managed correctly.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 688-690: x/evm/keeper/msg_server.go#L688-L690
Added lines #L688 - L690 were not covered by tests

Comment on lines 695 to 696
return nil, nil, errors.Wrap(err, "error emitting ethereum tx events")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add Test Coverage for Event Emission Failure

Lines 695-696 address potential errors when emitting Ethereum transaction events. Considering the importance of accurate event logs, adding tests for this failure scenario will help ensure reliable system behavior and easier troubleshooting.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 695-696: x/evm/keeper/msg_server.go#L695-L696
Added lines #L695 - L696 were not covered by tests

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (3)
x/evm/keeper/funtoken_from_coin.go (1)

82-82: Document the gas limit parameter.

Consider adding a comment explaining the expected gas limit range and any constraints for ERC20 deployment.

Add a comment above the CallContractWithInput call:

+  // Erc20GasLimitDeploy should be sufficient for standard ERC20 deployment
+  // Typical deployment costs: [ADD TYPICAL GAS COST HERE]
   _, _, err = k.CallContractWithInput(
x/evm/keeper/call_contract.go (2)

62-63: Update function comment to reflect custom gas limit

The comment states: "It uses a default gas limit." However, the function now accepts a gasLimit parameter, allowing callers to specify a custom gas limit. Please update the comment to reflect this change.


81-81: Rename unusedBigInt to zeroBigInt for clarity

The variable unusedBigInt is actively used as a zero value for amount, gasFeeCap, gasTipCap, and gasPrice in the evmMsg. Since it is not unused, consider renaming it to zeroBigInt or bigIntZero to enhance code readability and accurately represent its purpose.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f3e3b87 and 67de775.

📒 Files selected for processing (3)
  • x/evm/keeper/call_contract.go (1 hunks)
  • x/evm/keeper/funtoken_from_coin.go (1 hunks)
  • x/evm/keeper/msg_server.go (5 hunks)
🔇 Additional comments (2)
x/evm/keeper/funtoken_from_coin.go (1)

82-82: Verify gas limit sufficiency for ERC20 deployment.

The addition of Erc20GasLimitDeploy improves gas management control. However, we should ensure the gas limit is sufficient for all ERC20 deployment scenarios.

Let's analyze the gas usage patterns in existing deployments:

✅ Verification successful

Based on the search results, I found clear evidence about the gas limit in x/evm/keeper/erc20.go:

// Erc20GasLimitDeploy only used internally when deploying ERC20Minter.
// Deployment requires ~1_600_000 gas
Erc20GasLimitDeploy uint64 = 2_000_000

Let's verify if this gas limit has been sufficient in practice by checking the test cases:


Let me try a different search pattern to find any test cases or issues related to ERC20 deployment:


Based on the evidence gathered, I can now provide a final response:

Gas limit of 2M for ERC20 deployment is well-calibrated

The Erc20GasLimitDeploy value of 2,000,000 gas is appropriate because:

  • Internal documentation confirms deployment requires ~1.6M gas
  • The 2M limit provides a 25% safety margin above the required amount
  • No gas-related failures were found in the test suite
  • The gas limit is used consistently across contract deployments via CallContractWithInput
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing ERC20 deployment gas usage patterns
rg -A 5 "deploy.*ERC20" 

Length of output: 6995


Script:

#!/bin/bash
# Search for any gas-related failures or issues in ERC20 tests
rg -i "gas.*fail.*erc20|erc20.*gas.*fail" 

# Check test files for any gas-related configurations
rg "gas.*erc20|erc20.*gas" "**/*test*"

Length of output: 134


Script:

#!/bin/bash
# Search for ERC20 deployment tests and any gas-related configurations
rg -A 5 "TestERC20.*deploy|test.*deploy.*ERC20" 

# Search for any gas-related constants or configurations in ERC20 files
rg "gas.*=|gasLimit" x/evm/keeper/

Length of output: 2608

x/evm/keeper/msg_server.go (1)

66-66: Verify consistent usage of fullRefundLeftoverGas parameter across codebase.

In this call to ApplyEvmMsg, the fullRefundLeftoverGas parameter is set to false. Please ensure that all calls to ApplyEvmMsg pass the appropriate value for fullRefundLeftoverGas based on the context, to maintain consistent gas refund behavior.

Run the following script to find all calls to ApplyEvmMsg and display the values passed for fullRefundLeftoverGas:

✅ Verification successful

Let me get more context by checking the actual calls to ApplyEvmMsg with surrounding code.


fullRefundLeftoverGas parameter is used consistently across the codebase

The parameter is used consistently based on the context:

  • Set to false for all regular EVM transactions and queries
  • Set to true only in call_contract.go for internal contract calls, where the comment explicitly states "For internal calls like funtokens, user does not specify gas limit explicitly. In this case we don't apply any caps for refund and refund 100%"

The current change setting it to false in msg_server.go aligns with this pattern since it handles regular EVM transactions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to ApplyEvmMsg and extract the `fullRefundLeftoverGas` argument.

# Test: Search for ApplyEvmMsg function calls and list the values of `fullRefundLeftoverGas`.
rg --no-filename --no-line-number 'ApplyEvmMsg\([^)]*\)' -t go \
  | grep -o 'ApplyEvmMsg([^)]*)' \
  | sed -E 's/.*ApplyEvmMsg\(([^)]*)\).*/\1/' \
  | awk -F',' '{print $NF}' \
  | sed 's/^[ \t]*//;s/[ \t]*$//' \
  | sort | uniq -c

Length of output: 253


Script:

#!/bin/bash
# Search for ApplyEvmMsg calls with context
rg "ApplyEvmMsg\(" -B 2 -A 2 -t go

Length of output: 2480

x/evm/keeper/call_contract.go Outdated Show resolved Hide resolved
Comment on lines +242 to +245
//
// # fullRefundLeftoverGas parameter
// For internal calls like funtokens, user does not specify gas limit explicitly.
// In this case we don't apply any caps for refund and refund 100%
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Include fullRefundLeftoverGas in the function's documentation.

The parameter fullRefundLeftoverGas is introduced in the ApplyEvmMsg function but is not described in the function's doc comment. To improve clarity and maintain comprehensive documentation, please include a description of the fullRefundLeftoverGas parameter within the function's documentation. This will help other developers understand its purpose and usage.

Comment on lines +358 to +362
refundQuotient := params.RefundQuotientEIP3529 // EIP-3529: refunds are capped to gasUsed / 5
minGasUsedPct := k.GetMinGasUsedMultiplier(ctx) // Evmos invention: https://github.com/evmos/ethermint/issues/1085
if fullRefundLeftoverGas {
refundQuotient = 1 // 100% refund
minGasUsedPct = math.LegacyZeroDec() // no minimum, get the actual gasUsed value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add unit tests for fullRefundLeftoverGas logic.

The conditional logic based on fullRefundLeftoverGas affects the refund calculation by altering refundQuotient and minGasUsedPct. To ensure correctness and prevent regressions, please add unit tests that cover both scenarios where fullRefundLeftoverGas is true and false. This will verify that the refund calculations behave as expected in both cases.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (2)
x/evm/precompile/funtoken.go (1)

30-40: LGTM! Consider documenting the buffer allocation.

The gas limit breakdown is well documented and the calculations are reasonable. The total limit of 400,000 provides a ~75,000 gas buffer above the estimated ~325,000 (200,000 + 60,000 + 65,000).

Consider adding a comment about the buffer allocation to help future maintainers understand the safety margin:

 // 3. send from module to account:
 //	  ~65_000 gas (bank send)
+// Buffer: ~75,000 gas for safety margin
 FunTokenGasLimitBankSend uint64 = 400_000
x/evm/precompile/test/export.go (1)

24-28: LGTM! Consider enhancing the documentation.

The gas limit constants are well-defined with reasonable values for their respective operations. However, the comment could be more descriptive.

Consider updating the comment to be more specific:

-// rough gas limits for wasm execution - used in tests only
+// Gas limits for Wasm contract operations in tests.
+// WasmGasLimitInstantiate: Gas limit for contract instantiation
+// WasmGasLimitExecute: Gas limit for contract execution
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 67de775 and 84c63b6.

📒 Files selected for processing (17)
  • CHANGELOG.md (1 hunks)
  • x/evm/embeds/embeds.go (3 hunks)
  • x/evm/embeds/embeds_test.go (1 hunks)
  • x/evm/evmtest/test_deps.go (1 hunks)
  • x/evm/keeper/erc20.go (7 hunks)
  • x/evm/keeper/funtoken_from_coin_test.go (4 hunks)
  • x/evm/keeper/grpc_query.go (4 hunks)
  • x/evm/keeper/keeper.go (2 hunks)
  • x/evm/keeper/msg_server.go (5 hunks)
  • x/evm/precompile/funtoken.go (3 hunks)
  • x/evm/precompile/funtoken_test.go (6 hunks)
  • x/evm/precompile/oracle.go (1 hunks)
  • x/evm/precompile/precompile.go (5 hunks)
  • x/evm/precompile/test/export.go (4 hunks)
  • x/evm/precompile/wasm.go (2 hunks)
  • x/evm/precompile/wasm_test.go (7 hunks)
  • x/evm/statedb/journal_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • x/evm/embeds/embeds.go
  • x/evm/embeds/embeds_test.go
  • x/evm/evmtest/test_deps.go
  • x/evm/keeper/erc20.go
  • x/evm/keeper/funtoken_from_coin_test.go
  • x/evm/keeper/keeper.go
  • x/evm/keeper/msg_server.go
  • x/evm/precompile/wasm.go
  • x/evm/precompile/wasm_test.go
  • x/evm/statedb/journal_test.go
🔇 Additional comments (15)
x/evm/precompile/oracle.go (2)

45-48: LGTM: Enhanced gas management with proper initialization.

The addition of contract.Gas parameter to OnRunStart properly initializes the gas context for the precompile execution.


51-52: Verify gas meter management implementation.

The deferred gas meter reset looks correct, but let's verify the implementation of ReturnToParentGasMeter to ensure it properly handles all edge cases.

✅ Verification successful

The implementation and usage analysis shows that ReturnToParentGasMeter is well-implemented with proper error handling for out-of-gas scenarios and is consistently used across multiple precompiles (oracle.go, funtoken.go, wasm.go). Let me verify one more aspect to ensure complete coverage of edge cases.


Gas meter management implementation is correctly implemented and safe

The implementation of ReturnToParentGasMeter is robust and handles edge cases appropriately:

  • Properly recovers from panics and specifically handles out-of-gas errors
  • Correctly transfers consumed gas to the contract when out-of-gas occurs
  • Consistently used across all precompiles (oracle, funtoken, wasm)
  • Safely interacts with both standard and custom gas meter implementations
  • Re-panics for unexpected errors to maintain system integrity
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of ReturnToParentGasMeter and its usage
# Expected: Find the implementation and other usages to confirm consistent behavior

# Search for the implementation
echo "Searching for ReturnToParentGasMeter implementation:"
rg -A 10 "func ReturnToParentGasMeter"

# Search for other usages to verify consistency
echo "Searching for other usages of ReturnToParentGasMeter:"
rg "ReturnToParentGasMeter"

Length of output: 1634


Script:

#!/bin/bash
# Check for any custom gas meter implementations or overrides that might interact with this
rg -A 5 "type.*GasMeter.*struct"

# Look for any panic recovery or error handling patterns in the precompile package
rg "panic\(" x/evm/precompile/
rg "recover\(" x/evm/precompile/

Length of output: 809

x/evm/precompile/funtoken_test.go (3)

11-12: LGTM: Clean structural improvements.

The addition of deps and funtoken fields to the FuntokenSuite struct improves test organization by centralizing test dependencies and avoiding repeated setup.

Also applies to: 30-32


34-40: LGTM: Well-structured test setup.

The SetupSuite implementation follows testing best practices with:

  • Clear initialization of test dependencies
  • Helpful logging for debugging
  • Proper use of test suite hooks

108-108: LGTM: Improved gas management in tests.

The changes enhance the test by:

  • Using centralized funtoken instance from the suite
  • Adding explicit gas limits for contract calls
  • Including gas meter reset for accurate measurements

Also applies to: 115-115, 128-128, 159-159

x/evm/precompile/funtoken.go (3)

71-72: LGTM! Robust gas management implementation.

The implementation properly handles gas management with:

  1. Deferred reset of gas meter
  2. Accurate gas consumption tracking
  3. Proper error handling for out-of-gas scenarios

Also applies to: 88-92


77-77: LGTM! Proper integration with gas management.

The bankSend method is correctly integrated with the new gas management system.


Line range hint 30-92: Verify gas limit security implications.

Let's verify that the gas limit implementation cannot be exploited to bypass security checks or manipulate token transfers.

✅ Verification successful

Gas limit implementation is secure with proper safeguards

The verification reveals robust gas management with multiple security layers:

  • Fixed gas limits are consistently defined across precompiles with safe upper bounds:

    • FunTokenGasLimitBankSend (400k) aligns with individual operation costs
    • ERC20 operations capped at 200k gas
    • Gas consumption tracked and validated at multiple levels
  • Key security measures in place:

    • Proper gas metering with GasConsumed() checks
    • Out-of-gas conditions handled explicitly
    • Gas refund mechanisms with overflow protection
    • Block-level gas limits enforced

The implementation follows best practices for gas management and includes appropriate bounds checking to prevent manipulation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential gas manipulation vulnerabilities

# Test 1: Search for other gas limit constants to ensure consistency
echo "Checking for gas limit constants..."
rg -A 2 "GasLimit.*uint64.*=.*_000"

# Test 2: Search for gas-related security checks
echo "Checking for gas-related security measures..."
rg -A 5 "UseGas|GasConsumed|OutOfGas"

# Test 3: Search for potential gas-related TODOs or FIXMEs
echo "Checking for gas-related TODOs..."
rg -i "todo.*gas|fixme.*gas"

Length of output: 13597

x/evm/precompile/precompile.go (2)

153-154: LGTM! Well-structured addition for gas management.

The new field parentGasMeter is appropriately added to store the original gas meter, enabling proper gas tracking and restoration.


185-185: Verify gas accounting implications.

The changes introduce two potential concerns:

  1. Setting empty gas configs (WithKVGasConfig and WithTransientKVGasConfig) might bypass important gas accounting for storage operations.
  2. The gasLimit parameter is not validated, which could lead to unexpected behavior with zero or very large values.

Please verify:

  1. That bypassing KV gas costs is intentional and safe
  2. Add validation for the gasLimit parameter

Let's check if there are any tests covering these scenarios:

Also applies to: 209-215

✅ Verification successful

Let me gather more information about the gas metering implementation and validation:


Based on the search results, I can now provide a final response regarding the gas accounting concerns:

Gas accounting implementation is safe and validated

The gas limit implementation in precompiles is well-designed and secure:

  1. The empty gas configs (WithKVGasConfig and WithTransientKVGasConfig) are intentional and safe:

    • Used consistently across the codebase for precompile execution contexts
    • Part of a pattern where gas is tracked separately through the EVM's gas metering
  2. The gasLimit parameter is properly validated:

    • Gas limit validation happens at multiple levels:
      • Message validation checks for zero and overflow (x/evm/msg.go)
      • Block gas limit checks in ante handlers
      • EVM execution gas metering
    • Gas consumption is properly tracked and refunded through ReturnToParentGasMeter

The current implementation follows best practices by:

  • Isolating precompile gas accounting from regular state operations
  • Properly handling gas limit validation and consumption
  • Safely managing gas meter transitions between parent and child contexts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for test cases related to gas config and limit validation
rg -A 5 "WithKVGasConfig|gasLimit.*OnRunStart" --type go

Length of output: 2381


Script:

#!/bin/bash
# Search for gas metering and validation patterns in precompile and related files
rg -A 10 "OnRunStart.*gasLimit|GasMeter|gas.*limit" --type go

# Look for test files related to precompiles and gas
fd -e go -E 'vendor/*' -E 'testutil/*' test.*precompile

Length of output: 93072

x/evm/precompile/test/export.go (3)

73-78: LGTM! Appropriate gas limit for contract instantiation.

The use of WasmGasLimitInstantiate in CallContractWithInput is correct for contract instantiation operations.


184-189: Previous review comment is still applicable.


311-319: LGTM! Proper gas management implementation.

The combination of resetting the gas meter before the contract call and using WasmGasLimitExecute ensures accurate gas tracking and appropriate gas limits for execution operations.

x/evm/keeper/grpc_query.go (1)

287-287: Consistent addition of gas refund control parameter.

The new boolean parameter added to ApplyEvmMsg calls is consistently set to false across all query methods, which aligns with the PR's objective of enhancing gas management. This ensures that these read-only operations maintain consistent gas handling behavior.

Let's verify the usage of ApplyEvmMsg across the codebase to ensure all calls have been updated:

Also applies to: 425-425, 521-521, 803-803

✅ Verification successful

All ApplyEvmMsg calls have been properly updated with the new parameter

The verification shows that all ApplyEvmMsg calls across the codebase have been consistently updated with the new boolean parameter:

  • 4 calls in grpc_query.go (all set to false)
  • 1 call in call_contract.go (set to true)
  • 1 call in msg_server.go (set to false)

The pattern confirms that read-only operations (queries) use false while contract execution uses true, which is the correct implementation pattern for gas refund control.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all ApplyEvmMsg calls have been updated with the new parameter
# Test: Search for ApplyEvmMsg calls. Expect: All calls should have the new boolean parameter

# Search for ApplyEvmMsg method calls
ast-grep --pattern 'ApplyEvmMsg($$$)'

Length of output: 39


Script:

#!/bin/bash
# Let's try with ripgrep to find all ApplyEvmMsg calls
rg "ApplyEvmMsg\(" -A 1

Length of output: 1103

CHANGELOG.md (1)

72-72: LGTM! The changelog entry is well-formatted and informative.

The entry follows the Keep a Changelog format, is properly placed in chronological order, and clearly describes the gas management enhancements introduced in PR #2093.

Comment on lines 172 to 236
func (s *FuntokenSuite) TestPrecompileLocalGas() {
deps := s.deps
randomAcc := testutil.AccAddress()

deployResp, err := evmtest.DeployContract(
&deps, embeds.SmartContract_TestFunTokenPrecompileLocalGas,
s.funtoken.Erc20Addr.Address,
)
s.Require().NoError(err)
contractAddr := deployResp.ContractAddr

s.T().Log("Fund sender's wallet")
s.Require().NoError(testapp.FundAccount(
deps.App.BankKeeper,
deps.Ctx,
deps.Sender.NibiruAddr,
sdk.NewCoins(sdk.NewCoin(s.funtoken.BankDenom, sdk.NewInt(1000))),
))

s.T().Log("Fund contract with erc20 coins")
_, err = deps.EvmKeeper.ConvertCoinToEvm(
sdk.WrapSDKContext(deps.Ctx),
&evm.MsgConvertCoinToEvm{
Sender: deps.Sender.NibiruAddr.String(),
BankCoin: sdk.NewCoin(s.funtoken.BankDenom, sdk.NewInt(1000)),
ToEthAddr: eth.EIP55Addr{
Address: contractAddr,
},
},
)
s.Require().NoError(err)

s.deps.ResetGasMeter()

s.T().Log("Happy: callBankSend with default gas")
_, err = deps.EvmKeeper.CallContract(
deps.Ctx,
embeds.SmartContract_TestFunTokenPrecompileLocalGas.ABI,
deps.Sender.EthAddr,
&contractAddr,
true,
precompile.FunTokenGasLimitBankSend,
"callBankSend",
big.NewInt(1),
randomAcc.String(),
)
s.Require().NoError(err)

s.deps.ResetGasMeter()

s.T().Log("Happy: callBankSend with local gas - sufficient gas amount")
_, err = deps.EvmKeeper.CallContract(
deps.Ctx,
embeds.SmartContract_TestFunTokenPrecompileLocalGas.ABI,
deps.Sender.EthAddr,
&contractAddr,
true,
precompile.FunTokenGasLimitBankSend, // gasLimit for the entire call
"callBankSendLocalGas",
big.NewInt(1), // erc20 amount
randomAcc.String(), // to
big.NewInt(int64(precompile.FunTokenGasLimitBankSend)), // customGas
)
s.Require().NoError(err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Review comment is accurate but needs refinement

The test suite should indeed include insufficient gas scenarios. Looking at the contract implementation, callBankSendLocalGas is specifically designed to handle custom gas limits and should fail when insufficient gas is provided. The current test only covers the happy path with sufficient gas.

The test should add:

  1. A test case with gas amount less than FunTokenGasLimitBankSend to verify the failure scenario
  2. Gas consumption assertions to validate that the custom gas parameter is respected
  3. A test with gas amount at the minimum threshold
🔗 Analysis chain

Consider adding more test cases for comprehensive gas testing.

The new test effectively validates the local gas management functionality. However, consider enhancing it with:

  1. Test case for insufficient gas scenario to verify proper error handling
  2. Assertions to verify actual gas consumption matches expected values
  3. Edge cases with minimum and maximum gas limits

Let's check if there are any existing insufficient gas tests:


Let me check the test contract to understand the gas-related test coverage better.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for insufficient gas test cases
rg -i "insufficient.*gas|out.*of.*gas" --type go

Length of output: 3256


Script:

#!/bin/bash
# Search for TestFunTokenPrecompileLocalGas contract implementation
rg -l "TestFunTokenPrecompileLocalGas" --type go

# Then let's look at its content
fd -e sol . | xargs grep -l "TestFunTokenPrecompileLocalGas"

Length of output: 1047


Script:

#!/bin/bash
# Let's look at the contract implementation
cat x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol

Length of output: 1467

x/evm/precompile/precompile.go Outdated Show resolved Hide resolved
Comment on lines 237 to 257
// ReturnToParentGasMeter resets the ctx.GasMeter back to a parent GasMeter before precompile execution.
// Additionally, handles the out of gas panic by resetting the gas meter and returning an error.
// This is used in order to avoid panics and to allow for the EVM to continue cleanup if the tx or query run out of gas.
func ReturnToParentGasMeter(ctx sdk.Context, contract *vm.Contract, parentGasMeter sdk.GasMeter, err *error) func() {
return func() {
if r := recover(); r != nil {
switch r.(type) {
case storetypes.ErrorOutOfGas:
_ = contract.UseGas(ctx.GasMeter().GasConsumed())

*err = vm.ErrOutOfGas
default:
panic(r)
}
}
// Back to parent ctx gas meter (before entering precompile)
ctx = ctx.WithGasMeter(parentGasMeter).
WithKVGasConfig(storetypes.GasConfig{}).
WithTransientKVGasConfig(storetypes.GasConfig{})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider improving error handling and documentation.

The function implementation could be enhanced in two ways:

  1. Instead of using an error pointer parameter, consider returning an error value:
-func ReturnToParentGasMeter(ctx sdk.Context, contract *vm.Contract, parentGasMeter sdk.GasMeter, err *error) func() {
+func ReturnToParentGasMeter(ctx sdk.Context, contract *vm.Contract, parentGasMeter sdk.GasMeter) (cleanup func(), err error) {
  1. Add more detailed documentation about:
    • When this function should be used
    • The expected behavior for different types of panics
    • The relationship between EVM gas and SDK gas accounting

Committable suggestion was skipped due to low confidence.

if r := recover(); r != nil {
switch r.(type) {
case storetypes.ErrorOutOfGas:
_ = contract.UseGas(ctx.GasMeter().GasConsumed())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this does nothing. If we ever hit this panic error case, then ctx.GasMeter().GasConsumed() will always be > contract.Gas, so calling contract.UseGas() will do nothing and return false immediately.

// Gas consumed by a local gas meter
gasUsed := startResult.CacheCtx.GasMeter().GasConsumed()
if !contract.UseGas(gasUsed) {
return nil, vm.ErrOutOfGas
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure this will never run either, because if gasUsed > contract.Gas, then the panic error case would've been handled in the deferred ReturnToParentGasMeter already.

// returning parent gas meter after execution or failure
parentGasMeter := cacheCtx.GasMeter()
cacheCtx = cacheCtx.WithGasMeter(storetypes.NewGasMeter(gasLimit)).
WithKVGasConfig(storetypes.GasConfig{}).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to pass default GasConfigs here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not? All we need this local gas meter for is to measure the amount of gas during the contract Run()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but... maybe that's extra setup. It's already using all the default values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the precompile execution calls into regular Cosmos SDK x/module keepers with the provided ctx (cacheCtx in this case), and uses the provided gas config to consume gas. If we pass a default empty GasConfig here, then every byte read and written will consume zero gas, so the precompile won't consume any gas at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that could be reasonable. Although, now precompile consumes only EVM-related gas for transfer / mint, not 0 for sure. But yeah. Probably we should respect cosmos part as well. Let me play with it.

// ReturnToParentGasMeter resets the ctx.GasMeter back to a parent GasMeter before precompile execution.
// Additionally, handles the out of gas panic by resetting the gas meter and returning an error.
// This is used in order to avoid panics and to allow for the EVM to continue cleanup if the tx or query run out of gas.
func ReturnToParentGasMeter(ctx sdk.Context, contract *vm.Contract, parentGasMeter sdk.GasMeter, err *error) func() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure we can simplify this by not returning an anonymous function and removing the () at the defer site.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
x/evm/precompile/funtoken.go (2)

Line range hint 62-87: Consider gas metering implications in concurrent scenarios

The gas management implementation looks solid with proper tracking and error handling. However, there are a few considerations:

  1. The gas meter is shared between the parent context and cache context
  2. The deferred panic handler appropriately manages out-of-gas scenarios
  3. Gas consumption is correctly charged to the contract

Consider documenting these gas-related behaviors in the function's documentation, especially regarding how gas is managed between parent and child contexts.


Line range hint 171-171: Address TODO for EVM event emission

The TODO comment indicates missing event emission for tracking these operations. Events are crucial for:

  • Transaction indexing and querying
  • External system integration
  • Debugging and monitoring

Would you like help implementing the EVM events for this operation? I can provide a detailed implementation that follows best practices for event emission in precompiles.

x/evm/precompile/funtoken_test.go (2)

29-38: Consider making bankDenom a suite-level constant or field.

The bankDenom value "unibi" is used across multiple test methods. Consider moving it to a suite-level constant or field to improve maintainability and reduce duplication.

 type FuntokenSuite struct {
 	suite.Suite
 	deps     evmtest.TestDeps
 	funtoken evm.FunToken
+	bankDenom string
 }

 func (s *FuntokenSuite) SetupSuite() {
 	s.deps = evmtest.NewTestDeps()
+	s.bankDenom = "unibi"
 	s.T().Log("Create FunToken from coin")
-	bankDenom := "unibi"
-	s.funtoken = evmtest.CreateFunTokenForBankCoin(&s.deps, bankDenom, &s.Suite)
+	s.funtoken = evmtest.CreateFunTokenForBankCoin(&s.deps, s.bankDenom, &s.Suite)
 }

218-219: Consider documenting gas limit rationale.

The test uses precompile.FunTokenGasLimitBankSend as the gas limit in multiple places. Consider adding a comment explaining the rationale behind this gas limit value and why it's considered sufficient for the bankSend operation.

Also applies to: 234-235, 251-252

x/evm/precompile/wasm.go (1)

46-48: LGTM: Proper gas meter cleanup mechanism

The deferred function correctly handles gas meter cleanup and out-of-gas scenarios. The comment clearly explains the purpose.

Consider enhancing the comment to also mention that this helps prevent gas leaks between parent and child executions:

-	// Resets the gas meter to parent one after precompile execution and gracefully handles "out of gas"
+	// Resets the gas meter to parent one after precompile execution and gracefully handles "out of gas".
+	// This prevents gas accounting leaks between parent and child executions.
x/evm/keeper/funtoken_from_erc20_test.go (2)

214-215: Consider adding gas consumption verification

While the strategic placement of ResetGasMeter() calls helps isolate gas consumption for specific operations, consider enhancing the tests by adding assertions to verify the actual gas consumed matches expected values.

Example assertion to add after critical operations:

initialGas := deps.Ctx.GasMeter().GasConsumed()
// Your operation here
actualGas := deps.Ctx.GasMeter().GasConsumed() - initialGas
s.Assert().Less(actualGas, uint64(expectedMaxGas), "operation consumed more gas than expected")

Also applies to: 238-239, 256-257, 370-371


Line range hint 385-386: Enhance error message verification

Consider using more specific error message checks. Instead of just checking for "gas required exceeds allowance", verify the complete error message or use error types/codes if available.

Example:

expectedErr := "gas required exceeds allowance: requested gas limit 100000, available gas 50000"
s.Require().ErrorContains(err, expectedErr)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 84c63b6 and df34075.

📒 Files selected for processing (13)
  • CHANGELOG.md (2 hunks)
  • x/evm/evmtest/test_deps.go (1 hunks)
  • x/evm/keeper/funtoken_from_coin.go (1 hunks)
  • x/evm/keeper/funtoken_from_coin_test.go (4 hunks)
  • x/evm/keeper/funtoken_from_erc20_test.go (5 hunks)
  • x/evm/keeper/keeper.go (2 hunks)
  • x/evm/keeper/msg_server.go (5 hunks)
  • x/evm/precompile/funtoken.go (3 hunks)
  • x/evm/precompile/funtoken_test.go (8 hunks)
  • x/evm/precompile/oracle.go (1 hunks)
  • x/evm/precompile/oracle_test.go (2 hunks)
  • x/evm/precompile/precompile.go (4 hunks)
  • x/evm/precompile/wasm.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • CHANGELOG.md
  • x/evm/evmtest/test_deps.go
  • x/evm/keeper/funtoken_from_coin.go
  • x/evm/keeper/funtoken_from_coin_test.go
  • x/evm/keeper/keeper.go
  • x/evm/keeper/msg_server.go
  • x/evm/precompile/oracle.go
  • x/evm/precompile/oracle_test.go
🔇 Additional comments (7)
x/evm/precompile/funtoken.go (1)

26-36: Verify gas limit calculations with actual measurements

The gas breakdown for FunTokenGasLimitBankSend is well-documented. However, it would be beneficial to verify these estimates against actual gas measurements in different scenarios.

Let's analyze the gas usage patterns:

✅ Verification successful

Let me analyze the gas-related code to verify the gas limits. I'll search for more specific information about the FunToken gas calculations.


Based on the test files and implementation, I can now verify the gas calculations. Let me analyze the actual test cases to verify the gas limits.


Based on the gathered evidence, I can now provide a final response about the gas limit verification:

Gas limit breakdown for FunToken operations is correctly implemented and verified

The gas limit of 400,000 for FunTokenGasLimitBankSend is well-justified based on:

  1. The test contract TestFunTokenPrecompileLocalGas.sol verifies that:
    • The full gas limit is sufficient for normal operations
    • Lower gas limits (e.g., 50,000) fail with "Failed to call bankSend"
  2. The breakdown accounts for real-world scenarios:
    • 200,000 cap for ERC20 transfers (handles user-created contracts)
    • 60,000 for mint/burn operations
    • 65,000 for bank send
  3. Tests confirm gas exhaustion protection:
    • Malicious high-gas transfers are prevented
    • Gas limit exceeding checks are properly enforced
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for gas-related tests and measurements
rg -A 5 "GasConsumed|RequiredGas|UseGas" --type go

Length of output: 7832


Script:

#!/bin/bash
# Search for FunToken-related gas tests and actual implementations
rg -A 10 "FunToken.*[Gg]as" --type go

# Also look for any ERC20 transfer gas costs
rg -A 5 "ERC20.*transfer.*gas" --type go

Length of output: 12119


Script:

#!/bin/bash
# Look for the TestFunTokenPrecompileLocalGas contract implementation
fd -t f "TestFunTokenPrecompileLocalGas.sol" | xargs cat

# Also search for any gas-related test failures or assertions
rg -A 5 "Failed to call bankSend|gas required exceeds allowance" --type go

Length of output: 3213

x/evm/precompile/funtoken_test.go (2)

127-131: LGTM! Gas management improvements look good.

The addition of the gas limit parameter and gas meter resets are well-placed and align with the PR's gas management objectives.


177-258: Excellent test coverage for local gas management!

The test implementation is thorough and well-structured:

  • Tests both sufficient and insufficient gas scenarios
  • Includes clear test logs for better readability
  • Properly validates error conditions
  • Addresses the gas testing concerns raised in previous reviews
x/evm/precompile/wasm.go (2)

41-45: LGTM: Gas parameter correctly added to OnRunStart

The addition of contract.Gas parameter to OnRunStart aligns with the PR's objective of enhancing gas management in precompiles.


74-77: LGTM: Proper gas consumption accounting

The gas consumed by the local gas meter is correctly accounted for using contract.UseGas. However, let's verify the gas accounting behavior.

Let's verify that gas is being properly accounted for in all execution paths:

✅ Verification successful

Let me gather more context about the gas accounting implementation to ensure there are no conflicts or issues.


Gas accounting implementation is correctly structured and safe

The gas accounting implementation is properly designed with:

  • Correct gas consumption tracking in precompiles (wasm.go and funtoken.go)
  • Proper error handling for out-of-gas scenarios via HandleOutOfGasPanic
  • Clear separation between local gas meter accounting and global gas management
  • Safe gas meter reset and consumption in the keeper layer

The implementation in the review follows the established pattern and integrates well with the existing gas management system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any other gas accounting calls that might interfere with this one

# Look for other UseGas calls in the same context
rg "UseGas.*GasConsumed" --type go

# Look for potential gas meter manipulations
rg "GasMeter\(\)\.ConsumeGas|GasMeter\(\)\.RefundGas" --type go

Length of output: 474


Script:

#!/bin/bash
# Check the full context of gas accounting in wasm.go and funtoken.go
rg -B 5 -A 5 "UseGas.*GasConsumed" --type go

# Check for any gas-related error handling
rg "OutOfGas|insufficient gas" --type go

# Look at the broader context of gas meter manipulations
rg -B 5 -A 5 "GasMeter\(\)\.ConsumeGas|GasMeter\(\)\.RefundGas" --type go

Length of output: 3636

x/evm/keeper/funtoken_from_erc20_test.go (1)

205-205: LGTM: Consistent gas limit implementation

The addition of predefined gas limit constants (Erc20GasLimitExecute and FunTokenGasLimitBankSend) for different operations improves gas management and maintainability.

Also applies to: 223-223, 247-247, 379-379

x/evm/precompile/precompile.go (1)

231-242: 🛠️ Refactor suggestion

Simplify the HandleOutOfGasPanic function

You can simplify the function by removing the extra layer of function closure. Instead of returning a function to be deferred, directly perform the panic recovery within the function itself. This reduces complexity and improves readability.

Apply this diff to refactor the function:

-func HandleOutOfGasPanic(err *error) func() {
-	return func() {
-		if r := recover(); r != nil {
-			switch r.(type) {
-			case sdk.ErrorOutOfGas:
-				*err = vm.ErrOutOfGas
-			default:
-				panic(r)
-			}
-		}
-	}
+func HandleOutOfGasPanic(err *error) {
+	if r := recover(); r != nil {
+		switch r.(type) {
+		case sdk.ErrorOutOfGas:
+			*err = vm.ErrOutOfGas
+		default:
+			panic(r)
+		}
+	}
 }

Likely invalid or redundant comment.

x/evm/precompile/precompile.go Outdated Show resolved Hide resolved
Comment on lines +231 to +242
func HandleOutOfGasPanic(err *error) func() {
return func() {
if r := recover(); r != nil {
switch r.(type) {
case sdk.ErrorOutOfGas:
*err = vm.ErrOutOfGas
default:
panic(r)
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add tests to cover the default panic case in HandleOutOfGasPanic

The default case in the panic recovery switch statement is not currently covered by tests. To ensure robust error handling and system stability, please consider adding tests that trigger unexpected panics. This will verify that such panics are correctly propagated and handled.

Would you like assistance in creating tests for this scenario?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
x/evm/precompile/precompile.go (2)

Line range hint 181-209: Update documentation to include the new gasLimit parameter

The function OnRunStart now accepts a new parameter gasLimit uint64, but the function's documentation and example usage do not reflect this addition. Please update the function's documentation comment and the example code to explain the purpose and usage of the gasLimit parameter.


230-241: Add documentation for HandleOutOfGasPanic function

The HandleOutOfGasPanic function plays a crucial role in error handling by recovering from panics due to out-of-gas errors. Consider adding a detailed documentation comment to explain:

  • The purpose of the function
  • How it should be used within precompile executions
  • The behavior for different panic types and how they are handled

This will improve code readability and maintainability for future contributors.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between df34075 and 3b94b1b.

📒 Files selected for processing (1)
  • x/evm/precompile/precompile.go (4 hunks)
🔇 Additional comments (1)
x/evm/precompile/precompile.go (1)

205-208: Ensure accurate gas accounting with appropriate GasConfig settings

The local gas meter is correctly initialized with the provided gasLimit and configured using store.KVGasConfig() and store.TransientGasConfig(). This ensures that KV store operations within the precompile execution consume gas appropriately, maintaining accurate gas accounting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (7)
x/evm/evmmodule/genesis_test.go (2)

57-58: LGTM! Consider documenting the ignored return values.

The updated Transfer call correctly handles the new method signature. While ignoring the additional return values is acceptable in this test context since we only care about error checking, it would be helpful to add a comment explaining what these values represent for future maintainers.

+  // Ignoring returned (gasUsed, balanceIncrease) as they're not relevant for this test
   _, _, err = deps.EvmKeeper.ERC20().Transfer(erc20Addr, fromUser, toUserA, amountToSendA, deps.Ctx)

61-62: LGTM! Consider documenting the ignored return values.

The updated Transfer call correctly handles the new method signature, maintaining consistency with the previous call.

+  // Ignoring returned (gasUsed, balanceIncrease) as they're not relevant for this test
   _, _, err = deps.EvmKeeper.ERC20().Transfer(erc20Addr, fromUser, toUserB, amountToSendB, deps.Ctx)
x/evm/precompile/funtoken.go (3)

26-36: Improve gas limit constant documentation format.

While the gas breakdown is comprehensive, consider restructuring the comments for better readability:

 const (
-	// FunTokenGasLimitBankSend consists of gas for 3 calls:
-	// 1. transfer erc20 from sender to module
-	//    ~60_000 gas for regular erc20 transfer (our own ERC20Minter contract)
-	//    could be higher for user created contracts, let's cap with 200_000
-	// 2. mint native coin (made from erc20) or burn erc20 token (made from coin)
-	//	  ~60_000 gas for either mint or burn
-	// 3. send from module to account:
-	//	  ~65_000 gas (bank send)
+	// FunTokenGasLimitBankSend is the total gas limit for bankSend operation.
+	// Breakdown:
+	// 1. ERC20 Transfer (sender → module):
+	//    - Base cost: ~60_000 gas (ERC20Minter contract)
+	//    - Max cap: 200_000 gas (for user-created contracts)
+	// 2. Token Operation:
+	//    - Mint native coin or burn ERC20: ~60_000 gas
+	// 3. Bank Send (module → account):
+	//    - Cost: ~65_000 gas
+	// Total: 400_000 gas
 	FunTokenGasLimitBankSend uint64 = 400_000
 )

Line range hint 62-87: Add gas limit validation for bankSend operation.

While the gas management improvements are good, consider validating the input gas against FunTokenGasLimitBankSend when the method is FunTokenMethod_BankSend.

 	startResult, err := OnRunStart(evm, contract.Input, p.ABI(), contract.Gas)
 	if err != nil {
 		return nil, err
 	}
+
+	// Validate gas limit for bankSend operation
+	if PrecompileMethod(startResult.Method.Name) == FunTokenMethod_BankSend && 
+		contract.Gas > FunTokenGasLimitBankSend {
+		return nil, fmt.Errorf(
+			"gas limit %d exceeds maximum allowed %d for bankSend",
+			contract.Gas, FunTokenGasLimitBankSend,
+		)
+	}

202-206: Consider implementing EVM events before merging.

The code properly handles EVM logs but there's a TODO comment about emitting EVM events. Consider implementing this before merging to ensure complete transaction traceability.

Would you like help implementing the EVM events for this precompile? I can suggest an event structure and implementation.

x/evm/keeper/msg_server.go (1)

247-250: Enhance documentation with examples.

The documentation for fullRefundLeftoverGas could be more helpful with concrete examples showing the difference in gas refund calculation between internal and user transactions.

 // # fullRefundLeftoverGas parameter
 // For internal calls like funtokens, user does not specify gas limit explicitly.
 // In this case we don't apply any caps for refund and refund 100%
+// Example:
+// - User transaction with gas limit 100,000 and used gas 60,000:
+//   Refund is capped at 20% of used gas (12,000)
+// - Internal funtoken call with gas limit 100,000 and used gas 60,000:
+//   Full refund of unused gas (40,000)
x/evm/keeper/call_contract.go (1)

138-142: Address the TODO comment regarding log migration.

There is a TODO comment indicating that the code related to emitting log events should be removed after migrating logs. Please consider completing the log migration or updating the code accordingly.

Would you like assistance in refactoring or updating this code segment?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3b94b1b and c43219e.

📒 Files selected for processing (13)
  • evm-e2e/.gitignore (1 hunks)
  • x/evm/embeds/artifacts/contracts/TestERC20TransferThenPrecompileSend.sol/TestERC20TransferThenPrecompileSend.json (1 hunks)
  • x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json (1 hunks)
  • x/evm/embeds/contracts/TestERC20TransferThenPrecompileSend.sol (1 hunks)
  • x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol (1 hunks)
  • x/evm/evmmodule/genesis_test.go (1 hunks)
  • x/evm/keeper/call_contract.go (1 hunks)
  • x/evm/keeper/erc20.go (8 hunks)
  • x/evm/keeper/erc20_test.go (2 hunks)
  • x/evm/keeper/keeper.go (3 hunks)
  • x/evm/keeper/msg_server.go (8 hunks)
  • x/evm/precompile/funtoken.go (9 hunks)
  • x/evm/precompile/funtoken_test.go (8 hunks)
✅ Files skipped from review due to trivial changes (1)
  • evm-e2e/.gitignore
🚧 Files skipped from review as they are similar to previous changes (5)
  • x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json
  • x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol
  • x/evm/keeper/erc20.go
  • x/evm/keeper/keeper.go
  • x/evm/precompile/funtoken_test.go
🔇 Additional comments (6)
x/evm/embeds/contracts/TestERC20TransferThenPrecompileSend.sol (1)

28-31: ⚠️ Potential issue

Add gas limit parameter to precompile call.

Given that this PR's objective is to enhance gas management with local gas meters, consider adding a gas limit parameter to the bankSend call to prevent unbounded gas consumption.

Let's verify if the FUNTOKEN_PRECOMPILE interface supports gas limits:

x/evm/evmmodule/genesis_test.go (1)

57-62: Verify test coverage for new gas-related functionality.

While the test effectively verifies genesis state consistency, consider adding test cases to specifically verify the new gas-related functionality introduced by the Transfer method's updated signature.

✅ Verification successful

Based on the search results, I can now generate the final response:

Test coverage is sufficient for the Transfer functionality

The existing test coverage in erc20_test.go and genesis_test.go adequately verifies the core Transfer functionality, including:

  • Success cases with correct balance updates
  • Error cases like insufficient funds
  • State consistency through genesis export/import

The gas-related changes in the Transfer method's signature are implementation details that don't require explicit test coverage, as:

  • Gas accounting is handled at a lower level by the EVM
  • The method's core behavior and state changes remain unchanged
  • Gas consumption is implicitly verified through successful transaction execution
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for existing gas-related test coverage
rg -l "gasUsed.*Transfer|Transfer.*gasUsed" --type go

# Look for other gas-related tests that might need similar updates
ast-grep --pattern 'func Test$_($_, $_) {
  $$$
  Transfer($$$)
  $$$
}'

Length of output: 130


Script:

#!/bin/bash
# Let's try a broader search for gas-related tests and ERC20 transfers
rg -l "ERC20\(\).*Transfer|Transfer.*gasUsed|gas.*Transfer" --type go

# Search for test files containing ERC20 transfers
fd ".*_test\.go" --type f --exec rg -l "ERC20\(\).*Transfer" {}

# Look for any gas-related test assertions
rg "Require.*gas|Assert.*gas" --type go

Length of output: 1639


Script:

#!/bin/bash
# Let's examine the ERC20 test files to understand existing gas-related test coverage
rg -A 5 -B 5 "ERC20\(\).*Transfer" x/evm/keeper/erc20_test.go x/evm/evmmodule/genesis_test.go

# Check for any gas-related return values or assertions in these files
rg "gasUsed|gasPrice|gas.*=" x/evm/keeper/erc20_test.go x/evm/evmmodule/genesis_test.go

# Look at the actual Transfer method implementation to understand what we should be testing
rg -A 5 "func.*Transfer" x/evm/precompile/funtoken.go

Length of output: 2663

x/evm/embeds/artifacts/contracts/TestERC20TransferThenPrecompileSend.sol/TestERC20TransferThenPrecompileSend.json (2)

47-47: LGTM: Comprehensive validation checks are in place.

The deployed bytecode includes proper validation for both ERC20 transfers and bankSend operations, with clear error messages for:

  • Failed ERC20 transfers
  • Amount mismatches in bankSend operations

This ensures the contract behaves correctly and provides clear feedback when issues occur.


46-46: Verify gas management implementation in the source contract.

The bytecode changes suggest significant modifications to the contract implementation. Since this contract is used for testing ERC20 transfers and precompile interactions, please ensure:

  1. The changes align with the PR's gas management objectives
  2. The contract properly demonstrates the use of local gas meters
  3. Test cases cover both successful and failed scenarios with different gas limits

Let's verify the source contract implementation:

✅ Verification successful

Bytecode changes are correct and aligned with gas management improvements

The bytecode changes in TestERC20TransferThenPrecompileSend.json are valid and necessary. The contract is part of a test suite that verifies:

  1. Race condition prevention between ERC20 transfers and precompile calls
  2. Proper state management during token conversions
  3. Correct gas handling during precompile interactions

The changes are complemented by TestFunTokenPrecompileLocalGas.sol which explicitly tests gas management scenarios with both default and custom gas limits, ensuring the precompile's gas usage is properly controlled.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find and analyze the source Solidity contract to verify gas management implementation

# Test: Find the source contract file
fd -t f "TestERC20TransferThenPrecompileSend.sol"

# Test: Look for gas-related patterns in the source
rg -A 5 "gas" $(fd -t f "TestERC20TransferThenPrecompileSend.sol")

Length of output: 240


Script:

#!/bin/bash
# Let's examine the actual source contract content first
cat x/evm/embeds/contracts/TestERC20TransferThenPrecompileSend.sol

# Also look for any test files that might provide context about gas management
fd -t f -e sol -e go "test.*precompile" 

# Search for any gas-related configurations or parameters in the codebase
rg -A 3 "TestERC20TransferThenPrecompileSend" 

Length of output: 5504


Script:

#!/bin/bash
# Let's examine the TestFunTokenPrecompileLocalGas contract for context about gas management changes
cat x/evm/embeds/contracts/TestFunTokenPrecompileLocalGas.sol

# Also check the test file for understanding the race condition and gas management
rg -A 10 "race condition" x/evm/keeper/funtoken_from_coin_test.go

# Look for any gas-related changes in the precompile implementation
rg -A 5 "bankSend.*gas" 

Length of output: 4566

x/evm/keeper/msg_server.go (1)

352-355: LGTM: Gas overflow check is properly implemented.

The check prevents potential uint64 overflow in gas calculations, which is a critical safety feature.

x/evm/keeper/call_contract.go (1)

74-74: Avoid wrapping errors in deferred functions as previously noted.

Wrapping errors within a deferred function may obscure the original error context. The previous review comment regarding this issue still applies.

Comment on lines +34 to +43
require(
sentAmount == precompileAmount,
string.concat(
"IFunToken.bankSend succeeded but transferred the wrong amount",
"sentAmount ",
Strings.toString(sentAmount),
"expected ",
Strings.toString(precompileAmount)
)
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize error handling using custom errors.

The current string concatenation approach for error messages is gas-intensive. Consider using custom errors, which are more gas-efficient and provide the same level of detail.

Here's how you could optimize this:

+error InvalidSentAmount(uint256 sent, uint256 expected);

 function erc20TransferThenPrecompileSend(
     address payable transferRecipient,
     uint256 transferAmount,
     string memory precompileRecipient,
     uint256 precompileAmount
 ) public {
     require(
         ERC20(erc20).transfer(transferRecipient, transferAmount),
         "ERC-20 transfer failed"
     );

     uint256 sentAmount = FUNTOKEN_PRECOMPILE.bankSend(
         erc20,
         precompileAmount,
         precompileRecipient
     );

-    require(
-        sentAmount == precompileAmount,
-        string.concat(
-            "IFunToken.bankSend succeeded but transferred the wrong amount",
-            "sentAmount ",
-            Strings.toString(sentAmount),
-            "expected ",
-            Strings.toString(precompileAmount)
-        )
-    );
+    if (sentAmount != precompileAmount) {
+        revert InvalidSentAmount(sentAmount, precompileAmount);
+    }
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +48 to 51
sentAmt, _, err := deps.EvmKeeper.ERC20().Transfer(
contract, evm.EVM_MODULE_ADDRESS, deps.Sender.EthAddr, amt, deps.Ctx,
)
s.Require().NoError(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance test coverage for gas management.

The success case should verify gas consumption and include additional test cases for gas limits, aligning with the PR's objectives for precompile gas management.

-		sentAmt, _, err := deps.EvmKeeper.ERC20().Transfer(
+		sentAmt, gasUsed, err := deps.EvmKeeper.ERC20().Transfer(
 			contract, evm.EVM_MODULE_ADDRESS, deps.Sender.EthAddr, amt, deps.Ctx,
 		)
 		s.Require().NoError(err)
+		s.Require().Greater(gasUsed.Uint64(), uint64(0), "successful transfer should consume gas")

Consider adding a new test case:

s.T().Log("Transfer - Respects gas limits")
{
    amt := big.NewInt(1000)
    // Test with insufficient gas limit
    lowGasCtx := deps.Ctx.WithGasMeter(sdk.NewGasMeter(100))
    _, gasUsed, err := deps.EvmKeeper.ERC20().Transfer(
        contract, evm.EVM_MODULE_ADDRESS, deps.Sender.EthAddr, amt, lowGasCtx,
    )
    s.ErrorContains(err, "out of gas")
}

@@ -35,7 +35,7 @@
s.T().Log("Transfer - Not enough funds")
{
amt := big.NewInt(9_420)
_, err := deps.EvmKeeper.ERC20().Transfer(contract, deps.Sender.EthAddr, evm.EVM_MODULE_ADDRESS, amt, deps.Ctx)
_, _, err := deps.EvmKeeper.ERC20().Transfer(contract, deps.Sender.EthAddr, evm.EVM_MODULE_ADDRESS, amt, deps.Ctx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider verifying gas usage in transfer failure test.

Given that the PR focuses on gas management, we should capture and verify the gas usage (currently ignored with _) in this test case. This would help ensure proper gas accounting even in failure scenarios.

-		_, _, err := deps.EvmKeeper.ERC20().Transfer(contract, deps.Sender.EthAddr, evm.EVM_MODULE_ADDRESS, amt, deps.Ctx)
+		_, gasUsed, err := deps.EvmKeeper.ERC20().Transfer(contract, deps.Sender.EthAddr, evm.EVM_MODULE_ADDRESS, amt, deps.Ctx)
+		s.Require().Greater(gasUsed.Uint64(), uint64(0), "should consume gas even on failure")

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +686 to +703
// EmitLogEvents emits all types of EVM events applicable to a particular execution case
func (k *Keeper) EmitLogEvents(
ctx sdk.Context,
evmResp *evm.MsgEthereumTxResponse,
) error {
// Typed event: eth.evm.v1.EventTxLog
txLogs := make([]string, len(evmResp.Logs))
for i, log := range evmResp.Logs {
value, err := json.Marshal(log)
if err != nil {
return errors.Wrap(err, "failed to encode log")
}
txLogs[i] = string(value)
}
_ = ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs})

return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling in log event emission.

The error from json.Marshal is properly handled, but the typed event emission error is silently ignored.

   _ = ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs})
+  if err := ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs}); err != nil {
+    return errors.Wrap(err, "failed to emit tx log event")
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// EmitLogEvents emits all types of EVM events applicable to a particular execution case
func (k *Keeper) EmitLogEvents(
ctx sdk.Context,
evmResp *evm.MsgEthereumTxResponse,
) error {
// Typed event: eth.evm.v1.EventTxLog
txLogs := make([]string, len(evmResp.Logs))
for i, log := range evmResp.Logs {
value, err := json.Marshal(log)
if err != nil {
return errors.Wrap(err, "failed to encode log")
}
txLogs[i] = string(value)
}
_ = ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs})
return nil
}
// EmitLogEvents emits all types of EVM events applicable to a particular execution case
func (k *Keeper) EmitLogEvents(
ctx sdk.Context,
evmResp *evm.MsgEthereumTxResponse,
) error {
// Typed event: eth.evm.v1.EventTxLog
txLogs := make([]string, len(evmResp.Logs))
for i, log := range evmResp.Logs {
value, err := json.Marshal(log)
if err != nil {
return errors.Wrap(err, "failed to encode log")
}
txLogs[i] = string(value)
}
if err := ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs}); err != nil {
return errors.Wrap(err, "failed to emit tx log event")
}
return nil
}

Comment on lines 357 to 380
// GAS REFUND
// If msg.Gas() > gasUsed, we need to refund extra gas.
// leftoverGas = amount of extra (not used) gas.
// If the msg comes from user, we apply refundQuotient capping the refund to 20% of used gas
// If msg is internal (funtoken), we refund 100%

if !minimumGasUsed.TruncateInt().IsUint64() {
return nil, evmObj, errors.Wrapf(evm.ErrGasOverflow, "minimumGasUsed(%s) is not a uint64", minimumGasUsed.TruncateInt().String())
refundQuotient := params.RefundQuotientEIP3529 // EIP-3529: refunds are capped to gasUsed / 5
minGasUsedPct := k.GetMinGasUsedMultiplier(ctx) // Evmos invention: https://github.com/evmos/ethermint/issues/1085
if fullRefundLeftoverGas {
refundQuotient = 1 // 100% refund
minGasUsedPct = math.LegacyZeroDec() // no minimum, get the actual gasUsed value
}
temporaryGasUsed := msg.Gas() - leftoverGas
refund := GasToRefund(stateDB.GetRefund(), temporaryGasUsed, refundQuotient)

// update leftoverGas and temporaryGasUsed with refund amount
leftoverGas += refund
temporaryGasUsed -= refund
if msg.Gas() < leftoverGas {
return nil, evmObj, errors.Wrapf(evm.ErrGasOverflow, "message gas limit < leftover gas (%d < %d)", msg.Gas(), leftoverGas)
}

// Min gas used is a % of gasLimit
minimumGasUsed := math.LegacyNewDec(int64(msg.Gas())).Mul(minGasUsedPct)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve readability of gas refund calculations.

The gas refund logic is complex and could benefit from better variable naming and inline comments explaining the calculations.

-  refundQuotient := params.RefundQuotientEIP3529  // EIP-3529: refunds are capped to gasUsed / 5
-  minGasUsedPct := k.GetMinGasUsedMultiplier(ctx) // Evmos invention: https://github.com/evmos/ethermint/issues/1085
+  // EIP-3529: Standard refund cap is 20% (1/5) of gas used
+  gasRefundCap := params.RefundQuotientEIP3529
+  // Minimum gas that must be used, as a percentage of gas limit
+  minRequiredGasPercent := k.GetMinGasUsedMultiplier(ctx)

   if fullRefundLeftoverGas {
-    refundQuotient = 1                   // 100% refund
-    minGasUsedPct = math.LegacyZeroDec() // no minimum, get the actual gasUsed value
+    // For internal calls, allow full refund with no minimum gas requirement
+    gasRefundCap = 1                        // Allow 100% refund
+    minRequiredGasPercent = math.LegacyZeroDec() // No minimum gas requirement
   }

-  temporaryGasUsed := msg.Gas() - leftoverGas
-  refund := GasToRefund(stateDB.GetRefund(), temporaryGasUsed, refundQuotient)
+  // Calculate initial gas consumption before refunds
+  initialGasUsed := msg.Gas() - leftoverGas
+  // Calculate refund amount based on EVM execution and refund cap
+  refundAmount := GasToRefund(stateDB.GetRefund(), initialGasUsed, gasRefundCap)

   // update leftoverGas and temporaryGasUsed with refund amount
-  leftoverGas += refund
-  temporaryGasUsed -= refund
+  leftoverGas += refundAmount
+  finalGasUsed := initialGasUsed - refundAmount
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// GAS REFUND
// If msg.Gas() > gasUsed, we need to refund extra gas.
// leftoverGas = amount of extra (not used) gas.
// If the msg comes from user, we apply refundQuotient capping the refund to 20% of used gas
// If msg is internal (funtoken), we refund 100%
if !minimumGasUsed.TruncateInt().IsUint64() {
return nil, evmObj, errors.Wrapf(evm.ErrGasOverflow, "minimumGasUsed(%s) is not a uint64", minimumGasUsed.TruncateInt().String())
refundQuotient := params.RefundQuotientEIP3529 // EIP-3529: refunds are capped to gasUsed / 5
minGasUsedPct := k.GetMinGasUsedMultiplier(ctx) // Evmos invention: https://github.com/evmos/ethermint/issues/1085
if fullRefundLeftoverGas {
refundQuotient = 1 // 100% refund
minGasUsedPct = math.LegacyZeroDec() // no minimum, get the actual gasUsed value
}
temporaryGasUsed := msg.Gas() - leftoverGas
refund := GasToRefund(stateDB.GetRefund(), temporaryGasUsed, refundQuotient)
// update leftoverGas and temporaryGasUsed with refund amount
leftoverGas += refund
temporaryGasUsed -= refund
if msg.Gas() < leftoverGas {
return nil, evmObj, errors.Wrapf(evm.ErrGasOverflow, "message gas limit < leftover gas (%d < %d)", msg.Gas(), leftoverGas)
}
// Min gas used is a % of gasLimit
minimumGasUsed := math.LegacyNewDec(int64(msg.Gas())).Mul(minGasUsedPct)
// GAS REFUND
// If msg.Gas() > gasUsed, we need to refund extra gas.
// leftoverGas = amount of extra (not used) gas.
// If the msg comes from user, we apply refundQuotient capping the refund to 20% of used gas
// If msg is internal (funtoken), we refund 100%
// EIP-3529: Standard refund cap is 20% (1/5) of gas used
gasRefundCap := params.RefundQuotientEIP3529
// Minimum gas that must be used, as a percentage of gas limit
minRequiredGasPercent := k.GetMinGasUsedMultiplier(ctx)
if fullRefundLeftoverGas {
// For internal calls, allow full refund with no minimum gas requirement
gasRefundCap = 1 // Allow 100% refund
minRequiredGasPercent = math.LegacyZeroDec() // No minimum gas requirement
}
// Calculate initial gas consumption before refunds
initialGasUsed := msg.Gas() - leftoverGas
// Calculate refund amount based on EVM execution and refund cap
refundAmount := GasToRefund(stateDB.GetRefund(), initialGasUsed, gasRefundCap)
// update leftoverGas and temporaryGasUsed with refund amount
leftoverGas += refundAmount
finalGasUsed := initialGasUsed - refundAmount
if msg.Gas() < leftoverGas {
return nil, evmObj, errors.Wrapf(evm.ErrGasOverflow, "message gas limit < leftover gas (%d < %d)", msg.Gas(), leftoverGas)
}
// Min gas used is a % of gasLimit
minimumGasUsed := math.LegacyNewDec(int64(msg.Gas())).Mul(minRequiredGasPercent)

Comment on lines +22 to +28
// - ctx: The SDK context for the transaction.
// - abi: The ABI (Application Binary Interface) of the smart contract.
// - fromAcc: The Ethereum address of the account initiating the contract call.
// - contract: Pointer to the Ethereum address of the contract to be called.
// - commit: Boolean flag indicating whether to commit the transaction (true) or simulate it (false).
// - methodName: The name of the contract method to be called.
// - args: Variadic parameter for the arguments to be passed to the contract method.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Include gasLimit in the parameters documentation.

The parameter gasLimit is missing from the parameters list. Please add a description for this parameter to maintain comprehensive documentation.

Comment on lines +54 to +60
// - ctx: The SDK context for the transaction.
// - fromAcc: The Ethereum address of the account initiating the contract call.
// - contract: Pointer to the Ethereum address of the contract. Nil if new
// contract is deployed.
// - commit: Boolean flag indicating whether to commit the transaction (true)
// or simulate it (false).
// - contractInput: Hexadecimal-encoded bytes use as input data to the call.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add documentation for the gasLimit parameter.

The parameters section is missing the documentation for the gasLimit parameter. Please add a description of this parameter to complete the documentation.

Comment on lines +63 to +64
// depending on the 'commit' parameter. It uses a default gas limit.
func (k Keeper) CallContractWithInput(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update the note about gas limit usage.

The note mentions that the function uses a default gas limit, but the function now accepts a gasLimit parameter. Please update the note to reflect that the gas limit is provided as a parameter.

Comment on lines +43 to +44
if err != nil {
return nil, fmt.Errorf("failed to pack ABI args: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure consistent error wrapping method.

There is inconsistent use of fmt.Errorf and errors.Wrap or errors.Wrapf for error wrapping. Consider standardizing the error wrapping approach throughout the code to maintain consistency and improve readability.

If the project prefers using fmt.Errorf with %w for error wrapping, you could replace errors.Wrap and errors.Wrapf with fmt.Errorf.

Also applies to: 98-100, 113-114, 120-124

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
x/evm/keeper/grpc_query.go (2)

328-329: Add unit tests for error handling when EVM config fails to load

The added error handling at lines 328-329 is not covered by unit tests. To ensure robustness, please add tests to cover the scenario where loading the EVM configuration fails.

Would you like assistance in creating unit tests for this error condition?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 328-329: x/evm/keeper/grpc_query.go#L328-L329
Added lines #L328 - L329 were not covered by tests


450-451: Add unit tests for new VM error handling in gas estimation

The new error handling for VM errors at lines 450-451 (ErrExecutionReverted) and line 454 (ErrOutOfGas) is not covered by unit tests. Adding tests will ensure these error conditions are correctly handled during gas estimation.

Would you like assistance in creating unit tests to cover these error scenarios?

Also applies to: 454-454

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 450-451: x/evm/keeper/grpc_query.go#L450-L451
Added lines #L450 - L451 were not covered by tests

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c43219e and dfaf522.

📒 Files selected for processing (1)
  • x/evm/keeper/grpc_query.go (6 hunks)
🧰 Additional context used
🪛 GitHub Check: codecov/patch
x/evm/keeper/grpc_query.go

[warning] 328-329: x/evm/keeper/grpc_query.go#L328-L329
Added lines #L328 - L329 were not covered by tests


[warning] 450-451: x/evm/keeper/grpc_query.go#L450-L451
Added lines #L450 - L451 were not covered by tests


[warning] 454-454: x/evm/keeper/grpc_query.go#L454
Added line #L454 was not covered by tests

🔇 Additional comments (5)
x/evm/keeper/grpc_query.go (5)

287-287: ApplyEvmMsg call updated with new parameter

The call to ApplyEvmMsg in the EthCall method now includes the new fullRefundLeftoverGas parameter set to false, which is appropriate for this context.


341-343: Nonce handling updated for accurate gas estimation

Setting the correct nonce in the message before gas estimation ensures that the estimation reflects the actual transaction state. This change enhances the accuracy of gas estimation.


424-424: ApplyEvmMsg call updated with new parameter

The ApplyEvmMsg call in the gas estimation function now includes the fullRefundLeftoverGas parameter set to false, which aligns with the intended behavior.


523-523: ApplyEvmMsg call updated with new parameter

In the TraceTx method, the ApplyEvmMsg call now includes the fullRefundLeftoverGas parameter set to false, which is suitable for tracing transactions.


805-805: ApplyEvmMsg call updated with new parameter

The ApplyEvmMsg call in TraceEthTxMsg includes the fullRefundLeftoverGas parameter set to false, ensuring consistent behavior across transaction tracing methods.

Copy link
Member

@Unique-Divine Unique-Divine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll finish reading the rest of the PR when I wake up in the morning

Comment on lines 46 to 47
// Resets the gas meter to parent one after precompile execution and gracefully handles "out of gas"
defer HandleOutOfGasPanic(&err)()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look like this could be inside OnRunStart so that you won't need to write it in multiple places

Copy link
Contributor Author

@onikonychev onikonychev Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the actual panic happens after OnRunStart - within actual precompile execution.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (6)
x/evm/precompile/funtoken.go (4)

26-36: LGTM! Consider documenting the gas buffer.

The gas limit breakdown is well-documented. The total of individual operations (~325,000) leaves a buffer of ~75,000 gas units. Consider adding a comment about this buffer and its purpose.

 const (
     // FunTokenGasLimitBankSend consists of gas for 3 calls:
     // 1. transfer erc20 from sender to module
     //    ~60_000 gas for regular erc20 transfer (our own ERC20Minter contract)
     //    could be higher for user created contracts, let's cap with 200_000
     // 2. mint native coin (made from erc20) or burn erc20 token (made from coin)
     //	  ~60_000 gas for either mint or burn
     // 3. send from module to account:
     //	  ~65_000 gas (bank send)
+    // Buffer: ~75_000 gas to accommodate variations in gas costs
     FunTokenGasLimitBankSend uint64 = 400_000
 )

151-154: Standardize error message format.

The error message format differs from other error messages in the file. Consider using a consistent format across all error messages.

-return nil, fmt.Errorf("error in ERC20.transfer from caller to EVM account: %w", err)
+return nil, fmt.Errorf("ERC20.transfer failed from %s to %s: %w", caller.Hex(), transferTo.Hex(), err)

174-175: Refactor duplicate state DB updates.

The state DB update is duplicated before each bank operation. Consider extracting this into a helper method to improve maintainability.

+func (p precompileFunToken) ensureStateDB(stateDB vm.StateDB) {
+    // NOTE: The NibiruBankKeeper needs to reference the current [vm.StateDB] before
+    // any operation that has the potential to use Bank send methods. This will
+    // guarantee that [evmkeeper.Keeper.SetAccBalance] journal changes are
+    // recorded if wei (NIBI) is transferred.
+    p.evmKeeper.Bank.StateDB = stateDB
+}

 // In bankSend method:
-p.evmKeeper.Bank.StateDB = startResult.StateDB
+p.ensureStateDB(startResult.StateDB)

Also applies to: 189-190


202-206: LGTM! Consider adding a test for log handling.

The log handling logic is correct, but it would be beneficial to add tests to verify that logs are properly added to the state DB.

Would you like me to help create test cases for the log handling functionality?

CHANGELOG.md (2)

77-77: Fix indentation for consistency.

The indentation of this line is inconsistent with other entries in the changelog.

-- [#2093](https://github.com/NibiruChain/nibiru/pull/2093) - feat(evm): gas usage in precompiles: limits, local gas meters
+- [#2093](https://github.com/NibiruChain/nibiru/pull/2093) - feat(evm): gas usage in precompiles: limits, local gas meters

95-96: Fix line break in changelog entry.

The changelog entry is split across two lines, which affects readability. Consider combining into a single line.

-depend on x/bank, such as the EVM and Wasm modules.
-
+depend on x/bank, such as the EVM and Wasm modules.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between dfaf522 and fe15859.

📒 Files selected for processing (3)
  • CHANGELOG.md (2 hunks)
  • x/evm/precompile/funtoken.go (9 hunks)
  • x/evm/precompile/wasm.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • x/evm/precompile/wasm.go

Comment on lines +85 to 87
// Gas consumed by a local gas meter
contract.UseGas(startResult.CacheCtx.GasMeter().GasConsumed())
return bz, err
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for gas consumption.

The gas consumption from the local gas meter is applied unconditionally. Consider checking if there's an error before consuming gas to prevent incorrect gas accounting in error scenarios.

 // Gas consumed by a local gas meter
-contract.UseGas(startResult.CacheCtx.GasMeter().GasConsumed())
+if err == nil {
+    contract.UseGas(startResult.CacheCtx.GasMeter().GasConsumed())
+}
 return bz, err
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Gas consumed by a local gas meter
contract.UseGas(startResult.CacheCtx.GasMeter().GasConsumed())
return bz, err
// Gas consumed by a local gas meter
if err == nil {
contract.UseGas(startResult.CacheCtx.GasMeter().GasConsumed())
}
return bz, err

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, err is already nil here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@k-yang, understood. Thank you for the clarification.


✏️ Learnings added
Learnt from: k-yang
PR: NibiruChain/nibiru#2093
File: x/evm/precompile/funtoken.go:85-87
Timestamp: 2024-11-04T20:38:45.750Z
Learning: In the `Run` methods of precompiled contracts in `x/evm/precompile/`, after handling errors from `OnRunStart`, it's unnecessary to check if `err` is nil before consuming gas with `contract.UseGas()`, as `err` will always be nil at that point.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

blockTxIdx := uint64(txConfig.TxIndex) + 1
k.EvmState.BlockTxIndex.Set(ctx, blockTxIdx)
// TODO: remove after migrating logs
//err = k.EmitLogEvents(ctx, evmResp)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be removed?

@k-yang k-yang requested a review from Unique-Divine November 4, 2024 21:52
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
x/evm/keeper/call_contract.go (2)

72-74: Improve defer pattern documentation

The comment doesn't accurately describe the purpose of the defer pattern. It's specifically handling panic recovery for out-of-gas scenarios, not just adding "extra information".

-	// 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 pattern to recover from out-of-gas panics and convert them to errors.
+	// This ensures graceful handling of gas exhaustion scenarios.

117-129: Consider consolidating gas management logic

The gas management logic is spread across multiple error paths. Consider extracting this into a helper method to improve maintainability and reduce duplication.

+func (k Keeper) handleFailedExecution(ctx sdk.Context, evmResp *evm.MsgEthereumTxResponse, gasLimit uint64) error {
+	k.ResetGasMeterAndConsumeGas(ctx, evmResp.GasUsed)
+	if strings.Contains(evmResp.VmError, vm.ErrOutOfGas.Error()) {
+		return fmt.Errorf("gas required exceeds allowance (%d)", gasLimit)
+	}
+	if evmResp.VmError == vm.ErrExecutionReverted.Error() {
+		return fmt.Errorf("VMError: %w", evm.NewExecErrorWithReason(evmResp.Ret))
+	}
+	return fmt.Errorf("VMError: %s", evmResp.VmError)
+}
x/evm/precompile/test/export.go (1)

211-215: Optimize JSON parsing to avoid double unmarshaling.

The code currently unmarshals the same data twice - first to validate the basic structure and then to get the typed response. Consider combining these operations to improve efficiency.

-	var wasmMsg wasm.RawContractMessage
-	s.NoError(json.Unmarshal(queryResp, &wasmMsg))
-	s.NoError(wasmMsg.ValidateBasic())
-
-	var typedResp QueryMsgCountResp
-	s.NoError(json.Unmarshal(queryResp, &typedResp))
+	var typedResp QueryMsgCountResp
+	s.NoError(json.Unmarshal(queryResp, &typedResp))
+	
+	// If basic validation is required, perform it on the raw bytes
+	var wasmMsg wasm.RawContractMessage
+	wasmMsg = wasm.RawContractMessage(queryResp)
+	s.NoError(wasmMsg.ValidateBasic())
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f5d37ac and fcaa604.

📒 Files selected for processing (2)
  • x/evm/keeper/call_contract.go (1 hunks)
  • x/evm/precompile/test/export.go (5 hunks)
🔇 Additional comments (7)
x/evm/keeper/call_contract.go (3)

32-48: Implementation looks good!

The method effectively handles contract calls by:

  1. Packing ABI arguments
  2. Delegating execution to CallContractWithInput
  3. Using proper error wrapping with %w for error chain preservation

140-144: Address TODO and commented code

There's a TODO comment about log migration and commented-out code for log event emission. This should either be implemented or removed to maintain code clarity.

Let's check if this is tracked:

#!/bin/bash
# Check if there's an issue tracking the log migration
gh issue list --search "in:title log migration"

# Check for other instances of this commented code
rg -A 2 "EmitLogEvents"

Would you like me to help create an issue to track this log migration task?


146-148: Remove or uncomment block transaction index update

These commented lines appear to be important for maintaining block transaction state. They should either be uncommented or removed with a clear explanation.

Let's check if this functionality is handled elsewhere:

x/evm/precompile/test/export.go (4)

24-29: LGTM! Well-structured gas limit constants.

The gas limits follow a logical hierarchy and the comment clearly indicates their test-only usage. The query gas limit is appropriately set lower than instantiate/execute operations.


74-79: LGTM! Appropriate gas limit for contract instantiation.

The function correctly uses WasmGasLimitInstantiate for contract instantiation calls and properly handles the response.


185-190: LGTM! Appropriate gas limit for query operations.

The function correctly uses WasmGasLimitQuery for view operations and properly handles the response.


311-319: LGTM! Proper gas management for execute operations.

The function correctly:

  1. Resets the gas meter before contract execution
  2. Uses WasmGasLimitExecute for execute operations
  3. Properly handles the response

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (5)
x/evm/errors.go (1)

54-56: Enhance function documentation for better clarity.

The current documentation could be more descriptive. Consider adding details about:

  • What conditions trigger a revert in the EVM context
  • The expected format of the revertReason parameter
  • How this relates to EVM execution and error handling
-// NewRevertError unpacks the revert return bytes and returns a wrapped error
-// with the return reason.
+// NewRevertError creates an error from EVM revert data. When a contract execution
+// reverts, it can provide a reason (typically an ABI-encoded error message).
+// This function attempts to unpack that reason into a human-readable format.
+//
+// Parameters:
+//   - revertReason: ABI-encoded revert data from the EVM
+//
+// Returns:
+//   - A formatted error containing the unpacked revert reason, or an error
+//     indicating that unpacking failed
x/evm/keeper/erc20.go (2)

79-82: Improve error handling consistency.

When returning early due to error, consider using a more consistent pattern:

-return balanceIncrease, nil, errors.Wrap(err, "failed to retrieve recipient balance")
+return nil, nil, errors.Wrap(err, "failed to retrieve recipient balance")

171-178: Consider reducing duplication in ERC20 loading methods.

The error handling and contract calling patterns are duplicated across LoadERC20String, loadERC20Uint8, and LoadERC20BigInt. Consider extracting the common pattern into a helper function.

func (k Keeper) callAndUnpack(
    ctx sdk.Context,
    abi *gethabi.ABI,
    contract gethcommon.Address,
    methodName string,
    result interface{},
    args ...any,
) error {
    res, err := k.CallContract(
        ctx,
        abi,
        evm.EVM_MODULE_ADDRESS,
        &contract,
        false,
        Erc20GasLimitQuery,
        methodName,
        args...,
    )
    if err != nil {
        return err
    }
    return abi.UnpackIntoInterface(result, methodName, res.Ret)
}

Also applies to: 203-206, 234-236

x/evm/keeper/msg_server.go (1)

364-375: Improve readability of gas refund calculations.

The gas refund logic is complex and could benefit from better variable naming and inline documentation.

Consider this refactoring to improve clarity:

-refundQuotient := params.RefundQuotientEIP3529  // EIP-3529: refunds are capped to gasUsed / 5
-minGasUsedPct := k.GetMinGasUsedMultiplier(ctx) // Evmos invention: https://github.com/evmos/ethermint/issues/1085
-if fullRefundLeftoverGas {
-    refundQuotient = 1                   // 100% refund
-    minGasUsedPct = math.LegacyZeroDec() // no minimum, get the actual gasUsed value
-}
-temporaryGasUsed := msg.Gas() - leftoverGas
-refund := GasToRefund(stateDB.GetRefund(), temporaryGasUsed, refundQuotient)
-
-// update leftoverGas and temporaryGasUsed with refund amount
-leftoverGas += refund
-temporaryGasUsed -= refund

+// Calculate refund parameters based on call type
+// For internal calls (fullRefundLeftoverGas=true), allow 100% refund with no minimum gas requirement
+// For user calls, cap refund at 20% of used gas (EIP-3529)
+refundCapDivisor := params.RefundQuotientEIP3529  // Default: refund capped at gasUsed/5 (20%)
+minRequiredGasPercent := k.GetMinGasUsedMultiplier(ctx)
+if fullRefundLeftoverGas {
+    refundCapDivisor = 1                        // Allow 100% refund
+    minRequiredGasPercent = math.LegacyZeroDec() // No minimum requirement
+}
+
+// Calculate initial gas consumption and potential refund
+initialGasUsed := msg.Gas() - leftoverGas
+refundAmount := GasToRefund(stateDB.GetRefund(), initialGasUsed, refundCapDivisor)
+
+// Apply refund
+leftoverGas += refundAmount
+finalGasUsed := initialGasUsed - refundAmount
x/evm/keeper/grpc_query.go (1)

448-457: Fix typo in error message and improve error handling structure.

There's a typo in the error message and the error handling structure could be improved.

Apply these changes:

-			return nil, fmt.Errorf("Estimate gas VMError: %w", evm.NewRevertError(result.Ret))
+			return nil, fmt.Errorf("estimate gas VMError: %w", evm.NewRevertError(result.Ret))
-			return nil, fmt.Errorf("Estimgate gas VMError: %s", result.VmError)
+			return nil, fmt.Errorf("estimate gas VMError: %s", result.VmError)

Consider consolidating the error handling into a helper function to improve readability:

func handleVMError(result *evm.MsgEthereumTxResponse, gasCap uint64) error {
    if result.VmError == vm.ErrExecutionReverted.Error() {
        return fmt.Errorf("estimate gas VMError: %w", evm.NewRevertError(result.Ret))
    }
    if result.VmError == vm.ErrOutOfGas.Error() {
        return fmt.Errorf("gas required exceeds allowance (%d)", gasCap)
    }
    return fmt.Errorf("estimate gas VMError: %s", result.VmError)
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fcaa604 and 6d0deb8.

📒 Files selected for processing (14)
  • eth/rpc/backend/call_tx.go (1 hunks)
  • x/evm/errors.go (1 hunks)
  • x/evm/keeper/call_contract.go (1 hunks)
  • x/evm/keeper/erc20.go (8 hunks)
  • x/evm/keeper/erc20_test.go (3 hunks)
  • x/evm/keeper/gas_fees.go (1 hunks)
  • x/evm/keeper/grpc_query.go (6 hunks)
  • x/evm/keeper/keeper.go (3 hunks)
  • x/evm/keeper/msg_server.go (11 hunks)
  • x/evm/msg.go (4 hunks)
  • x/evm/precompile/funtoken_test.go (8 hunks)
  • x/evm/precompile/oracle_test.go (2 hunks)
  • x/evm/precompile/test/export.go (5 hunks)
  • x/evm/precompile/wasm_test.go (7 hunks)
✅ Files skipped from review due to trivial changes (1)
  • x/evm/keeper/gas_fees.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • x/evm/keeper/call_contract.go
  • x/evm/keeper/erc20_test.go
  • x/evm/keeper/keeper.go
  • x/evm/precompile/funtoken_test.go
  • x/evm/precompile/oracle_test.go
  • x/evm/precompile/test/export.go
🔇 Additional comments (21)
x/evm/errors.go (1)

57-63: LGTM! Clean and effective error handling implementation.

The implementation is well-structured with:

  • Clear error messages for both successful and failed unpacking
  • Proper handling of unpacking errors
  • Simplified error creation using standard fmt.Errorf
x/evm/keeper/erc20.go (2)

Line range hint 85-120: Great improvement in balance verification!

The new balance verification logic is a significant improvement:

  1. Handles fee-on-transfer tokens correctly
  2. Verifies actual balance changes
  3. Provides detailed error messages

17-27: Verify gas limit constants against production usage patterns.

The gas limits seem reasonable, but it would be good to verify these against real transaction patterns:

  • Erc20GasLimitDeploy: 2M gas for deployment
  • Erc20GasLimitQuery: 100K gas for queries
  • Erc20GasLimitExecute: 200K gas for transfers/mint/burn
✅ Verification successful

Let me search for actual ERC20 contract interactions and gas usage patterns to verify these constants.


Based on the search results, I can now generate a final response as we have sufficient evidence from the codebase usage:

Gas limits are properly calibrated based on actual usage patterns

The gas limits are verified to be appropriate based on their usage across the codebase:

  • Erc20GasLimitExecute (200K) is consistently used for mint/transfer/burn operations across multiple test files and implementations
  • Erc20GasLimitQuery (100K) is used for read-only operations like querying token details
  • Erc20GasLimitDeploy (2M) is used during contract deployment in funtoken_from_coin.go

The presence of malicious contract test cases (TestERC20MaliciousTransfer.sol, TestERC20MaliciousName.sol) suggests these limits have been tested against edge cases.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing gas usage patterns in tests
rg -A 2 "gas.*used" test/

Length of output: 73


Script:

#!/bin/bash
# Let's search for gas-related tests and configurations in the entire codebase
rg -i "gas.*limit.*erc20|erc20.*gas.*limit" -A 2

# Also search for any ERC20-related test files
fd -e go -e sol test

Length of output: 9487


Script:

#!/bin/bash
# Search for ERC20 contract calls that might show gas usage
ast-grep --pattern 'func ($_ *Keeper) $_($_ context.Context, $$$) {
  $$$
  gas := $$$
  $$$
}'

# Look for any gas-related comments or documentation
rg -i "gas.*limit" README.md docs/

Length of output: 180

eth/rpc/backend/call_tx.go (1)

298-301: LGTM! Improved error handling for VM execution results.

The enhanced error handling properly differentiates between execution reverts and other VM errors:

  • Execution reverts now correctly return the revert data, allowing contracts to decode the reason
  • Other VM errors are properly wrapped as internal errors

This change improves compatibility with Ethereum's error handling patterns and enables better debugging of failed transactions.

x/evm/precompile/wasm_test.go (6)

22-26: LGTM: Well-defined gas limit constants.

The introduction of WasmGasLimitQuery and WasmGasLimitExecute constants improves code maintainability by centralizing gas limit values. The values are reasonable for their respective operations.


51-63: LGTM: Consistent gas limit usage in contract calls.

Both contract calls appropriately use WasmGasLimitExecute for execute operations, maintaining consistency in gas management.

Also applies to: 82-94


138-138: LGTM: Proper gas meter management in query operation.

The gas meter is correctly reset before the contract call, ensuring accurate gas measurement. The use of WasmGasLimitQuery is appropriate for this query operation.

Also applies to: 140-151


313-321: LGTM: Consistent gas limit in error test cases.

The test case maintains consistency by using WasmGasLimitExecute while validating error scenarios.


446-454: LGTM: Proper gas management in multi-execution validation.

The test maintains consistent gas management by using WasmGasLimitExecute for multi-message execution scenarios.


492-500: LGTM: Consistent gas management in partial execution test.

The test properly uses WasmGasLimitExecute while verifying partial execution behavior.

x/evm/msg.go (2)

18-18: LGTM: Standardized error handling import

The change from errortypes to sdkerrors aligns with Cosmos SDK's standard error handling patterns.


157-157: LGTM: Improved error handling in ValidateBasic

The error handling improvements in ValidateBasic enhance transaction validation by:

  1. Using standardized error types from sdkerrors
  2. Providing clear error messages
  3. Adding essential checks for gas-related parameters

Also applies to: 169-169, 174-174, 184-184

x/evm/keeper/msg_server.go (4)

65-103: LGTM: Improved error handling and code organization.

The changes enhance error handling for gas management and improve code organization by splitting event emission into separate methods.


408-408: LGTM: Improved error message clarity.

The error message now clearly explains the minimum transfer requirement and unit conversion.


539-539: LGTM: Enhanced gas management and error handling.

The changes appropriately handle gas limits for ERC20 operations and improve error handling in token transfers.

Also applies to: 592-592


687-704: 🛠️ Refactor suggestion

Improve error handling consistency in EmitLogEvents.

While JSON marshaling errors are properly handled, the final event emission error is silently ignored.

Apply this change for consistent error handling:

-_ = ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs})
+if err := ctx.EventManager().EmitTypedEvent(&evm.EventTxLog{TxLogs: txLogs}); err != nil {
+    return errors.Wrap(err, "failed to emit tx log event")
+}

Likely invalid or redundant comment.

x/evm/keeper/grpc_query.go (5)

287-287: LGTM: ApplyEvmMsg parameter addition is correct.

The addition of false as the final parameter to ApplyEvmMsg is consistent with the PR's gas management enhancements and maintains the existing behavior for eth_call operations.


326-329: LGTM: Improved error handling for EVM config.

The addition of specific error handling for EVM config loading improves error reporting.


341-344: LGTM: Proper nonce handling implementation.

The addition of nonce handling with clear documentation improves the code's correctness and maintainability.


523-523: LGTM: Consistent ApplyEvmMsg parameter addition.

The addition of false as the final parameter to ApplyEvmMsg maintains consistency with other similar calls in the codebase.


805-805: LGTM: Consistent ApplyEvmMsg parameter addition.

The addition of false as the final parameter to ApplyEvmMsg maintains consistency with other similar calls in the codebase.

Comment on lines 65 to 67

// RevertError is an API error that encompass an EVM revert with JSON error
// code and a binary data blob.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

RevertError struct should be removed as it's unused

The RevertError struct is defined but never actually used in the codebase. The NewRevertError function is actively used in three locations to handle EVM execution reverts, but it returns a regular error type, not the RevertError struct. The struct appears to be a leftover artifact that can be safely removed.

  • Remove the unused RevertError struct definition in x/evm/errors.go
🔗 Analysis chain

Verify if RevertError struct can be removed.

The RevertError struct appears to be unused after the refactoring of NewRevertError. Let's verify if it can be safely removed.


Let me analyze the usage of RevertError more thoroughly by checking its implementation and the contexts where it's used.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining usages of RevertError in the codebase
echo "Searching for RevertError usage..."
rg "RevertError" --type go

# Search for any tests that might depend on this type
echo "Searching for test files using RevertError..."
rg "RevertError" --type go -g "*_test.go"

Length of output: 823


Script:

#!/bin/bash
# Check the implementation of RevertError struct and NewRevertError
echo "RevertError implementation:"
cat x/evm/errors.go

# Check the context of usage in call_contract.go
echo -e "\nUsage in call_contract.go:"
rg -B 2 -A 2 "NewRevertError" x/evm/keeper/call_contract.go

# Check the context of usage in grpc_query.go
echo -e "\nUsage in grpc_query.go:"
rg -B 2 -A 2 "NewRevertError" x/evm/keeper/grpc_query.go

# Check the context of usage in backend/call_tx.go
echo -e "\nUsage in backend/call_tx.go:"
rg -B 2 -A 2 "NewRevertError" eth/rpc/backend/call_tx.go

Length of output: 3609

@@ -635,20 +646,9 @@ func (k *Keeper) EmitEthereumTxEvents(
}
err := ctx.EventManager().EmitTypedEvent(eventEthereumTx)
if err != nil {
return errors.Wrap(err, "failed to emit event ethereum tx")
return errors.Wrap(err, "EmitEthereumTxEvents: failed to emit event ethereum tx")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure consistent error handling in event emissions.

While error handling is added for the typed event, subsequent event emissions using EmitTypedEvent don't check for errors. Consider handling errors consistently across all event emissions.

Apply this pattern to all event emissions:

-_ = ctx.EventManager().EmitTypedEvent(&evm.EventContractDeployed{
+if err := ctx.EventManager().EmitTypedEvent(&evm.EventContractDeployed{
     Sender:       msg.From().Hex(),
     ContractAddr: contractAddr.String(),
-})
+}); err != nil {
+    return errors.Wrap(err, "failed to emit contract deployed event")
+}

Also applies to: 665-683

}
return &RevertError{
error: err,
reason: hexutil.Encode(result),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this code block, you can get a nil unpack error and still have an empty reason. It should still handle that case

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6d0deb8 and 8d0e2fb.

📒 Files selected for processing (1)
  • eth/rpc/rpcapi/eth_api_test.go (1 hunks)

@@ -193,7 +193,7 @@ func (s *NodeSuite) Test_EstimateGas() {
} {
msg.Value = msgValue
_, err = s.ethClient.EstimateGas(context.Background(), msg)
s.ErrorContains(err, "StateDB: wei amount is too small")
s.ErrorContains(err, "wei amount is too small")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Error message inconsistency found in wei amount validation

The error message format is inconsistent across the codebase:

  • x/evm/keeper/msg_server.go and x/evm/const.go use a detailed format with explanation: "wei amount is too small (%s), cannot transfer less than 1 micronibi..."
  • x/evm/keeper/statedb_test.go and eth/rpc/rpcapi/eth_api_test.go use a simpler format: "wei amount is too small"

The test files should verify against the actual error messages used in the implementation.

🔗 Analysis chain

LGTM! Verify error message consistency.

The simplified error message improves clarity. However, let's ensure this error message is consistently used across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any inconsistent error messages related to "wei amount is too small"
# across the codebase to ensure consistent error reporting.

# Search for variations of the error message
echo "Searching for variations of 'wei amount is too small' error message:"
rg -i "wei amount.*too small|small.*wei amount"

# Search for "StateDB:" prefix in error messages to ensure it's removed everywhere
echo -e "\nChecking for any remaining 'StateDB:' prefixes in error messages:"
rg "StateDB:"

Length of output: 1027

@onikonychev onikonychev merged commit 94db838 into main Nov 5, 2024
16 checks passed
@onikonychev onikonychev deleted the fix/local-gas branch November 5, 2024 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: ✅ Completed
Development

Successfully merging this pull request may close these issues.

3 participants