Cosmos EVM

repository·main·Indexed 41 days ago

https://github.com/cosmos/evm

A plug-and-play solution for adding Ethereum Virtual Machine (EVM) compatibility and customizability to Cosmos SDK chains. It enables the execution of Solidity smart contracts, support for Ethereum JSON-RPC tooling, and IBC asset bridging. Key features include the ability to define custom EIPs to modify opcode behavior via the EVMConfigurator and a dual-pool mempool architecture that manages both Ethereum and Cosmos transactions.

Tokens
55K
Snippets
162
Records
214
Agent score
51%

What's inside Cosmos EVM

  1. Use the ICS02 Precompile to interact with IBC light clients

    main
    The ICS02 precompile provides an EVM interface to the IBC-Go 02-client module. This allows smart contracts to interact with IBC light clients using the ICS-02 standard. The precompile is located at the fixed address: 0x0000000000000000000000000000000000000807.
  2. Use the Slashing Precompile to manage validator status

    main

    The Slashing precompile provides an EVM interface to the Cosmos SDK slashing module. It allows smart contracts to monitor validator liveness (signing information), retrieve slashing parameters, and enables jailed validators to unjail themselves once their jail period has expired.

    Precompile Address: 0x00000000000000000000000000000000000000806

    ISlashing slashing = ISlashing(0x0000000000000000000000000000000000000806);
  3. What is the WERC20 Precompile?

    main

    The WERC20 (Wrapped ERC20) precompile provides a wrapped ERC20 interface for the native EVM token, similar to WETH on Ethereum. It allows the native token to be used in smart contracts that expect ERC20 tokens, enabling compatibility with DeFi protocols and other ERC20-based applications without actually locking native tokens in a contract.

    Key differences from traditional WETH:

    • No Actual Wrapping: Tokens remain as native tokens; only the interface changes.
    • No Lock-up: Native tokens are never locked in the precompile.
    • Automatic Reflection: Native balance changes are immediately reflected in the ERC20 view.
    • Withdraw No-op: The withdraw function exists for interface compatibility but does not perform transfers.
  4. How the ERC20 Precompile handles transfers and metadata

    main

    Transfer Mechanism

    • Direct transfers (transfer): Executes a bank send message from the caller to the recipient.
    • Delegated transfers (transferFrom): Checks and updates the spender's allowance, then executes a bank send message from the token owner to the recipient. It emits both Transfer and Approval events.

    Metadata Resolution

    Token metadata (name, symbol, decimals) is resolved using this priority:

    1. Bank module metadata (if registered).
    2. IBC voucher base denomination (for IBC tokens).
    3. Inferred from denomination (e.g., uatom → name: "Atom", symbol: "ATOM", decimals: 6).

    Balance Integration

    • Balances are read directly from the Cosmos SDK bank keeper.
    • Transfers use bank send messages for state changes.
    • The EVM native token undergoes a 18 decimal conversion.
  5. Use the ERC20 Precompile to interact with native Cosmos SDK coins

    main

    The ERC20 precompile allows smart contracts within the EVM to manage native Cosmos SDK coins using the standard ERC20 interface. Instead of wrapping native tokens into a contract, you can call the precompile address associated with a specific TokenPair (which maps a Cosmos SDK denomination to an ERC20 contract address). This enables seamless interaction between EVM smart contracts and the Cosmos SDK bank module.

    // Assuming the precompile is deployed at a specific address for a native token
    IERC20 token = IERC20(0x...); // Precompile address for the native token
    
    // Check balance
    uint256 balance = token.balanceOf(msg.sender);
    
    // Transfer tokens
    token.transfer(recipient, 1000000); // Transfer 1 token (assuming 6 decimals)
    
    // Approve and transferFrom
    token.approve(spender, 5000000);
    // Spender can now call:
    token.transferFrom(owner, recipient, 3000000);
  6. How the IBC testing package components work together

    main

    The IBC testing package is organized into a four-layer stack to simulate Inter-Blockchain Communication (IBC) environments. Understanding the hierarchy is essential for setting up complex testing scenarios:

    1. Coordinator: The highest level. It manages all initialized chains and maintains a global synchronized time via TimeIncrement. It provides utility functions to set up clients, connections, and channels between chains.
    2. Chain: Represents an SDK application (defined by an app.go file). It uses a TestingApp to simulate block production and transaction processing. It typically contains a single CometBFT validator and processes SDK messages.
    3. Path: A logical connection between two channel endpoints. It holds the necessary information to relay packets from one endpoint to another.
    4. Endpoint: Represents a specific channel (including its client and connections) on a specific chain. Endpoints are used to execute IBC logic (sending, receiving, and acknowledging packets) and hold references to both their local chain and their counterparty endpoint.

    Workflow Summary:

    • Use endpoints to initialize and execute IBC logic on one side of a connection.
    • Use paths to relay packets between endpoints.
    • Use chains to commit SDK messages.
    • Use the coordinator to establish a path between two chains.
  7. Use the Distribution Precompile

    main

    The Distribution precompile at address 0x00000000000000000000000000000000000000801 provides an EVM interface to the Cosmos SDK x/distribution module. It allows smart contracts to interact with staking rewards, validator commissions, and the community pool. It supports both reward queries and distribution operations like claiming, withdrawing, and funding. The precompile supports both hex and bech32 address formats, performing automatic conversion for Cosmos SDK compatibility.

    address distributionPrecompile = 0x00000000000000000000000000000000000000801;
  8. How EVM nonce gaps are handled

    main

    When an EVM transaction is submitted with a nonce gap (e.g., submitting nonce 5 when the current nonce is 3), the CheckTx handler catches the ErrNonceGap error.

    Instead of returning a failure to the client, the system calls InsertInvalidNonce(). This queues the transaction locally in the TxPool. The transaction remains in this state until the missing nonces are filled, at which point the BroadcastTxFn callback is triggered to broadcast the transactions via the Comet mempool.

  9. Handle funds in destination-side EVM callbacks

    main

    When using destination-side callbacks, funds are sent to an ephemeral isolated address generated from the channelId and the packet sender.

    Critical Limitation: No user can sign messages on behalf of this isolated account. If your destination contract receives funds and attempts to deposit them back into msg.sender (the isolated address), the tokens will become unreachable.

    Best Practice: Your destination contract must be designed to forward the received tokens to a specific, user-controlled address provided within the calldata. If the target contract does not support this, you must use a wrapper contract that:

    1. Receives the funds.
    2. Calls the target contract.
    3. Moves the funds from the target contract to a final desired address.
  10. Security and Error Handling in the ERC20 Precompile

    main

    Security Considerations

    • No Direct Funding: The precompile address cannot receive funds via msg.value. This prevents accidental loss of funds sent directly to the precompile.
    • Allowance Management: Follows standard ERC20 patterns with strict checks.
    • Balance Consistency: All state changes are routed through the Cosmos SDK bank module to ensure system-wide consistency.

    Error Handling

    • The precompile validates transfer amounts and allowances.
    • It converts Cosmos SDK bank module errors into ERC20-compatible error formats.
  11. How EVM Callbacks work with ICS-20 transfers

    main

    EVM Callbacks allow for atomic cross-chain operations by executing an EVM contract call on the destination chain immediately upon receiving an ICS-20 transfer packet. This is achieved by utilizing the memo field in the IBC packet to pass execution instructions.

    Execution Flow

    1. Core IBC Checks: Standard checks (timeout, replay) are performed.
    2. Validation: The module ensures the packet is correctly formatted and the receiver is set to the required isolated address.
    3. EVM Execution: The requested EVM contract call is executed. If the call fails, the entire recvPacket application state is reverted, and an error acknowledgement is returned.

    Key Constraints

    • Isolated Receiver: To prevent spoofing, the receiver must be an isolated address derived from the channel ID and the sender: sdkaddress.Module("ibc-callbacks", packet.destChannelId, packet.sender).
    • Sender Identity: The sender in the EVM call is replaced with a module-prefixed account to prevent confusion with local users. Warning: Due to a known bug in packet forward middleware, do not trust the sender address in contracts executed via IBC callbacks.
    {
        "data":{
        	"denom": "denom on counterparty chain",
            "amount": "1000",
            "sender": "addr on counterparty chain",
            "receiver": "isolated_receiver_address_for_sender",
        	"memo": {
               "dest_callback": {
                  "address": "evmContractAddress",
                  "gas_limit": "1000000",
                  "calldata": "{abipacked_contract_calldata}",
                }
            }
        }
    }
  12. Use the P256 Precompile for secp256r1 signature verification

    main

    The P256 precompile implements secp256r1 (P-256/prime256v1) elliptic curve signature verification as defined in EIP-7212. It allows smart contracts to verify signatures from devices like WebAuthn authenticators, secure enclaves, and hardware security modules (HSMs).

    Key Details:

    • Address: 0x0000000000000000000000000000000000000100
    • Gas Cost: Fixed at 3,450 gas (constant regardless of input).
    • Interface: Operates at a low level via staticcall. It accepts a 160-byte raw input and returns a 32-byte verification result.
    • Output: Returns 0x00...01 (1) on success. Returns empty data or 32 zero bytes on failure. Returns empty data if input length is invalid.
    contract P256Verifier {
        address constant P256_PRECOMPILE = 0x0000000000000000000000000000000000000100;
        
        function verifySignature(
            bytes32 messageHash,
            bytes32 r,
            bytes32 s,
            bytes32 x,
            bytes32 y
        ) public view returns (bool) {
            bytes memory input = abi.encodePacked(messageHash, r, s, x, y);
            (bool success, bytes memory result) = P256_PRECOMPILE.staticcall(input);
            
            if (success && result.length == 32) {
                uint256 verification = abi.decode(result, (uint256));
                return verification == 1;
            }
            return false;
        }
    }