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: add precompile for calling bank to evm from evm #2135

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

matthiasmatt
Copy link
Contributor

@matthiasmatt matthiasmatt commented Dec 30, 2024

This pull request includes several changes to the CHANGELOG.md file and the IFunToken.json file to fix bugs, add new features, and simplify the code. The most important changes include fixing a missing error check, adding new precompile functions, and updating the changelog with the latest changes.

Bug Fixes and Improvements:

  • CHANGELOG.md: Fixed a bug where the err != nil check was missing in the bankBalance precompile method. This ensures that errors are properly handled in the precompile function.

New Features:

Summary by CodeRabbit

  • New Features

    • Added two new methods to the FunToken interface: sendToEvm and bankMsgSend
    • Enhanced token transfer capabilities between Nibiru and Ethereum ecosystems
  • Chores

    • Updated CHANGELOG.md with formatting improvements
    • Updated contract artifacts and bytecode for several test contracts
  • Tests

    • Added test cases for new sendToEvm and bankMsgSend methods

@matthiasmatt matthiasmatt requested a review from a team as a code owner December 30, 2024 23:30
Copy link
Contributor

coderabbitai bot commented Dec 30, 2024

Walkthrough

This pull request introduces two new methods to the IFunToken interface and its corresponding precompile implementation: sendToEvm and bankMsgSend. These methods enhance the interoperability between Nibiru's bank module and the EVM ecosystem by allowing token transfers between bank coins and ERC-20 tokens. The changes include updates to the contract interface, precompile implementation, and associated test cases, with corresponding artifact and changelog modifications to document these additions.

Changes

File Change Summary
CHANGELOG.md Reformatted entries, added documentation for PRs #2119, #2120, #2124, #2125
x/evm/embeds/contracts/IFunToken.sol Added two new methods: sendToEvm and bankMsgSend to the interface
x/evm/precompile/funtoken.go Implemented sendToEvm and bankMsgSend methods in precompile struct
x/evm/precompile/funtoken_test.go Added test cases for sendToEvm and bankMsgSend methods
x/evm/precompile/precompile.go Updated isMutation map with new method entries
Multiple x/evm/embeds/artifacts/contracts/*.json Updated bytecode for various test contracts

Sequence Diagram

sequenceDiagram
    participant Sender
    participant EVM
    participant BankModule
    participant FunToken

    Sender->>EVM: Call sendToEvm()
    EVM->>FunToken: Validate transfer
    FunToken->>BankModule: Deduct bank coins
    FunToken->>EVM: Mint/Transfer ERC20 tokens
    EVM-->>Sender: Return sent amount

    Sender->>EVM: Call bankMsgSend()
    EVM->>FunToken: Validate send parameters
    FunToken->>BankModule: Execute bank transfer
    BankModule-->>Sender: Return success status
Loading

Assessment against linked issues

Objective Addressed Explanation
Method IFunToken.sendToEvm: Send Bank Coins to the EVM state as ERC20 tokens (2049)
Method IFunToken.bankMsgSend: Make an EVM call that calls "/cosmos.bank.v1beta1.MsgSend" (2049)

Possibly related issues

Poem

🐰 Tokens dancing, bank and EVM unite,
Precompiles sparkling with coding might!
Send and transfer with rabbit-like grace,
Bridging worlds at lightning-fast pace.
CodeRabbit's magic makes blockchain bright! 🌟


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1fd8a32 and 129cbb1.

📒 Files selected for processing (1)
  • CHANGELOG.md (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

@matthiasmatt matthiasmatt requested review from Copilot and removed request for a team December 30, 2024 23:33
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 4 out of 11 changed files in this pull request and generated 1 comment.

Files not reviewed (7)
  • x/evm/embeds/artifacts/contracts/IFunToken.sol/IFunToken.json: Language not supported
  • x/evm/embeds/artifacts/contracts/TestERC20TransferThenPrecompileSend.sol/TestERC20TransferThenPrecompileSend.json: Language not supported
  • x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json: Language not supported
  • x/evm/embeds/artifacts/contracts/TestInfiniteRecursionERC20.sol/TestInfiniteRecursionERC20.json: Language not supported
  • x/evm/embeds/artifacts/contracts/TestNativeSendThenPrecompileSend.sol/TestNativeSendThenPrecompileSend.json: Language not supported
  • x/evm/embeds/artifacts/contracts/TestPrecompileSelfCallRevert.sol/TestPrecompileSelfCallRevert.json: Language not supported
  • x/evm/embeds/contracts/IFunToken.sol: Language not supported
Comments suppressed due to low confidence (2)

x/evm/precompile/funtoken.go:551

  • [nitpick] The error message 'no funtoken found for bank denom "%s"' could be more descriptive to help users understand the context better.
return nil, fmt.Errorf("no funtoken found for bank denom \"%s\"", bankDenom)

x/evm/precompile/funtoken.go:731

  • The error message for argument type validation in 'parseArgsBankMsgSend' should be more explicit to indicate the expected and received types.
err = ErrArgTypeValidation("string to", args[0])

// 0) bankDenom
bankDenom, ok = args[0].(string)
if !ok {
err = ErrArgTypeValidation("string bankDenom", args[0])
Copy link
Preview

Copilot AI Dec 30, 2024

Choose a reason for hiding this comment

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

The error message for argument type validation in 'parseArgsSendToEvm' should be more explicit to indicate the expected and received types.

Suggested change
err = ErrArgTypeValidation("string bankDenom", args[0])
err = fmt.Errorf("expected string for bankDenom, got %T", args[0])

Copilot is powered by AI, so mistakes are possible. Review output carefully before use.

Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
Copy link

codecov bot commented Dec 30, 2024

Codecov Report

Attention: Patch coverage is 51.82927% with 79 lines in your changes missing coverage. Please review.

Project coverage is 65.03%. Comparing base (1ae53e4) to head (129cbb1).

Files with missing lines Patch % Lines
x/evm/precompile/funtoken.go 51.82% 55 Missing and 24 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2135      +/-   ##
==========================================
- Coverage   65.10%   65.03%   -0.07%     
==========================================
  Files         274      274              
  Lines       21732    21896     +164     
==========================================
+ Hits        14148    14240      +92     
- Misses       6610     6657      +47     
- Partials      974      999      +25     
Files with missing lines Coverage Δ
x/evm/precompile/precompile.go 60.82% <ø> (ø)
x/evm/precompile/funtoken.go 58.14% <51.82%> (-1.02%) ⬇️

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

🧹 Nitpick comments (5)
x/evm/precompile/funtoken.go (2)

529-587: Emit EVM events when transferring tokens
While this function neatly handles the logic for transferring bank coins to ERC20, consider adding an event emission at the end for success/failure. An event can help frontends track or confirm the completion of cross-chain transfers more easily.


677-713: Optionally emit events for bankMsgSend
The function successfully transfers coins to the recipient and returns a boolean indicating success. Consider emitting additional EVM events to provide clients with immediate feedback on send operations, parallel to the standard approach in most EVM-based contracts.

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

432-490: Comprehensive test coverage for sendToEvm
This test scenario covers minting and transferring flows thoroughly. As an additional check, consider adding a negative test case for sending zero or insufficient funds to enhance robustness.


492-559: Validations in bankMsgSend test
The test ensures proper final balances and a success return value. Adding a failing test where the sender lacks enough balance or uses an invalid recipient address could provide valuable edge-case coverage.

x/evm/embeds/artifacts/contracts/TestInfiniteRecursionERC20.sol/TestInfiniteRecursionERC20.json (1)

Line range hint 1-313: Ensure test coverage for recursive precompile calls.

Given this contract tests infinite recursion scenarios and the PR implements bank-to-EVM precompile functionality, we should verify that recursive precompile calls are properly tested.

Consider adding test cases to specifically verify:

  1. Maximum recursion depth for bank-to-EVM calls
  2. Error handling for recursive precompile calls
  3. Gas consumption patterns in recursive scenarios
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 666a58d and 48e6f7e.

📒 Files selected for processing (11)
  • CHANGELOG.md (4 hunks)
  • x/evm/embeds/artifacts/contracts/IFunToken.sol/IFunToken.json (2 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/artifacts/contracts/TestInfiniteRecursionERC20.sol/TestInfiniteRecursionERC20.json (1 hunks)
  • x/evm/embeds/artifacts/contracts/TestNativeSendThenPrecompileSend.sol/TestNativeSendThenPrecompileSend.json (1 hunks)
  • x/evm/embeds/artifacts/contracts/TestPrecompileSelfCallRevert.sol/TestPrecompileSelfCallRevert.json (1 hunks)
  • x/evm/embeds/contracts/IFunToken.sol (1 hunks)
  • x/evm/precompile/funtoken.go (3 hunks)
  • x/evm/precompile/funtoken_test.go (1 hunks)
  • x/evm/precompile/precompile.go (1 hunks)
✅ Files skipped from review due to trivial changes (5)
  • x/evm/embeds/artifacts/contracts/TestERC20TransferThenPrecompileSend.sol/TestERC20TransferThenPrecompileSend.json
  • x/evm/embeds/artifacts/contracts/TestPrecompileSelfCallRevert.sol/TestPrecompileSelfCallRevert.json
  • x/evm/embeds/artifacts/contracts/TestNativeSendThenPrecompileSend.sol/TestNativeSendThenPrecompileSend.json
  • CHANGELOG.md
  • x/evm/embeds/artifacts/contracts/TestFunTokenPrecompileLocalGas.sol/TestFunTokenPrecompileLocalGas.json
🔇 Additional comments (15)
x/evm/precompile/funtoken.go (8)

45-46: New methods recognized
The introduction of two new precompile method constants (FunTokenMethod_sendToEvm and FunTokenMethod_bankMsgSend) is well-named and consistent with the existing naming convention.


77-80: Switch cases for new methods
These new switch cases neatly integrate sendToEvm and bankMsgSend into the existing precompile flow. The logic for routing to the correct methods appears consistent with the rest of the code.


589-633: Mint or unescrow logic seems correct
This helper function correctly distinguishes between owner-minted and escrow-based ERC20 tokens. Thorough checks for balances before/after unescrow ensure correctness.


635-640: Argument parsing structure is consistent
The top-level argument parsing for sendToEvm follows the same pattern used in other parse functions. The number of arguments is validated before accessing them.


642-645: Improve error message for argument type
This is similar to a past comment () requesting that the type mismatch error include both the expected and received type. For example:

- err = ErrArgTypeValidation("string bankDenom", args[0])
+ err = fmt.Errorf("expected string for bankDenom, got %T", args[0])

646-660: Remainder of parse logic
The subsequent checks for the amount and to fields look correct. Proper early returns on type validation errors are in place.


662-675: Address parsing logic
The logic for detecting Ethereum hex vs. Bech32 addresses is robust. The clear error messages facilitate troubleshooting invalid addresses.


715-744: Argument parsing for bankMsgSend
The function’s argument checks (type validation, positive amount requirement) are consistent. There are no obvious gaps in error handling.

x/evm/embeds/contracts/IFunToken.sol (2)

56-73: Definition of sendToEvm
This added interface method accurately reflects the usage in the precompile code, ensuring that the receiver can be either an EVM hex address or a Bech32 address. The documentation comment is comprehensive.


74-87: Definition of bankMsgSend
The newly introduced interface method aligns with the Cosmos bank module's send semantics. The return value being a boolean for success is a straightforward design choice.

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

230-231: Marking sendToEvm and bankMsgSend as mutations
Classifying these methods as state-mutating in isMutation is correct, given they both transfer tokens. This ensures proper gas calculation and event handling.

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

129-157: bankMsgSend ABI entry
The ABI entry correctly mirrors the contract function’s signature and aligns with the implementation in the precompile.


187-215: sendToEvm ABI entry
This ABI addition accurately matches the newly introduced contract function, ensuring the JSON artifact remains up-to-date with the code.

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

Line range hint 1-311: Security test contract implementation looks good.

The contract implements necessary ERC20 functions and includes specific test methods for security testing. The presence of attackBalance and attackTransfer methods indicates proper test coverage for potential recursive call vulnerabilities.


312-313: Verify bytecode changes against source modifications.

The bytecode has been updated, which could indicate changes in the contract's implementation. Let's verify these changes match the source.

✅ Verification successful

Let me check the contract source to verify the bytecode changes.


Bytecode changes are consistent with the contract source

The bytecode changes in the JSON artifact file correspond to the compiled version of the TestInfiniteRecursionERC20 contract. The contract is designed to test infinite recursion scenarios through precompile interactions, specifically:

  1. balanceOf - Implements recursive behavior through staticcall to FUNTOKEN_PRECOMPILE_ADDRESS
  2. transfer - Implements recursive behavior through FUNTOKEN_PRECOMPILE.sendToBank
  3. Attack functions that trigger the recursive behaviors

The bytecode reflects these implementations and the contract's inheritance from OpenZeppelin's ERC20.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify contract source matches bytecode
# Look for the source file and any recent changes

# Find the source file
fd -t f "TestInfiniteRecursionERC20.sol"

# Check for any imports or dependencies in the contract
rg -A 5 "^import.*TestInfiniteRecursionERC20"

# Look for any recent changes to the contract
rg "contract TestInfiniteRecursionERC20"

Length of output: 286


Script:

#!/bin/bash
# Get the contract source code
cat x/evm/embeds/contracts/TestInfiniteRecursionERC20.sol

Length of output: 1281

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

🧹 Nitpick comments (4)
x/evm/precompile/funtoken_test.go (4)

432-490: Consider adding edge cases to TestSendToEvm.

The test thoroughly covers the happy path, but would benefit from additional test cases:

  • Invalid amounts (zero or negative)
  • Non-existent denominations
  • Insufficient balance scenarios

492-559: Add failure scenarios to TestBankMsgSend.

While the success path is well-tested, consider adding test cases for:

  • Invalid recipient addresses
  • Zero or negative amounts
  • Non-existent denominations
  • Insufficient balance scenarios
    This would help ensure proper error handling and validation.

566-653: Improve test readability and maintainability.

Consider the following improvements:

  1. Define constants for commonly used values (500, 100 tokens)
  2. Extract the ERC20 deployment and funding setup into a helper function
  3. Create a helper function for the repeated balance assertion pattern

Example refactor:

+const (
+    INITIAL_SUPPLY = 1000000
+    INITIAL_TRANSFER = 500
+    TEST_TRANSFER = 100
+)

+func setupTestERC20WithFunding(deps *evmtest.TestDeps, recipient gethcommon.Address) (gethcommon.Address, error) {
+    // Deploy ERC20
+    erc20Resp, err := evmtest.DeployContract(deps, embeds.SmartContract_TestERC20)
+    if err != nil {
+        return gethcommon.Address{}, err
+    }
+    
+    // Transfer initial amount
+    deployerAddr := gethcommon.HexToAddress(erc20Resp.EthTxMsg.From)
+    _, err = deps.EvmKeeper.CallContract(
+        deps.Ctx,
+        embeds.SmartContract_TestERC20.ABI,
+        deployerAddr,
+        &erc20Resp.ContractAddr,
+        true,
+        keeper.Erc20GasLimitExecute,
+        "transfer",
+        recipient,
+        bigTokens(INITIAL_TRANSFER),
+    )
+    return erc20Resp.ContractAddr, err
+}

561-564: Improve helper function documentation and constants.

Consider these improvements:

  1. Define TOKEN_DECIMALS as a named constant
  2. Add a more descriptive comment explaining the purpose and usage
+const TOKEN_DECIMALS_MULTIPLIER = 1_000_000_000_000_000_000 // 1e18: Standard ERC20 decimals

+// bigTokens converts a human-readable token amount to its smallest unit representation
+// by multiplying it with 1e18 (standard ERC20 decimals)
 func bigTokens(n int64) *big.Int {
-    e18 := big.NewInt(1_000_000_000_000_000_000) // 1e18
+    e18 := big.NewInt(TOKEN_DECIMALS_MULTIPLIER)
     return new(big.Int).Mul(big.NewInt(n), e18)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48e6f7e and 1fd8a32.

📒 Files selected for processing (1)
  • x/evm/precompile/funtoken_test.go (1 hunks)

); err != nil {
return nil, fmt.Errorf("failed to send coins to module: %w", err)
}

Copy link
Member

@k-yang k-yang Jan 3, 2025

Choose a reason for hiding this comment

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

I think you're missing the burn call here, in the case the funtoken mapping was created from the EVM side.

wantBank := big.NewInt(234) // 1234 - 1000 => 234
bankBal := deps.App.BankKeeper.GetBalance(deps.Ctx, deps.Sender.NibiruAddr, bankDenom).Amount.BigInt()
s.EqualValues(wantBank, bankBal, "did user lose 1000 unibi from bank?")

Copy link
Member

Choose a reason for hiding this comment

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

Can we also check the EVM module account's balance.

}

func bigTokens(n int64) *big.Int {
e18 := big.NewInt(1_000_000_000_000_000_000) // 1e18
Copy link
Member

Choose a reason for hiding this comment

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

(nit) could just do big.NewInt(1e18) to not have the reader manually count the number of zeroes.

// no bank side left
balAfter := deps.App.BankKeeper.GetBalance(deps.Ctx, alice.NibiruAddr, bankBal.Denom).Amount.BigInt()
s.Require().EqualValues(bigTokens(0), balAfter)

Copy link
Member

Choose a reason for hiding this comment

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

Can you also check the EVM module account's balance? It should be zero as well here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[evm] Minimalist precompile for x/bank
2 participants