Skip to main content

Overview

Precompiles allow EVM contracts to interact directly with native chain modules. Precompiles are special contract addresses that execute native Go code instead of EVM bytecode.

All Standard EVM Precompiles

MANTRA Chain supports all standard EVM precompiles that are available on Ethereum and other EVM-compatible chains. These precompiles work identically to how they work on Ethereum, Base, Polygon, Arbitrum, and other EVM chains.

Standard Ethereum Precompiles

All of the following standard EVM precompiles are available and fully functional:
  1. ECRecover (0x01) - Elliptic curve signature recovery
  2. SHA256 (0x02) - SHA-256 hash function
  3. RIPEMD160 (0x03) - RIPEMD-160 hash function
  4. Identity (0x04) - Data copying function
  5. ModExp (0x05) - Modular exponentiation
  6. BN256Add (0x06) - Elliptic curve addition on the BN256 curve
  7. BN256Mul (0x07) - Elliptic curve scalar multiplication on the BN256 curve
  8. BN256Pairing (0x08) - Bilinear pairing on the BN256 curve
  9. Bls12-381 (0x09-0x0F) - BLS12-381 curve operations
These precompiles behave exactly as they do on Ethereum and other EVM chains, ensuring full compatibility with existing EVM contracts and libraries.

Additional Cosmos SDK Precompiles

In addition to all standard EVM precompiles, MANTRA Chain exposes additional precompiles that let developers interact with the CosmWasm (CW) side of the chain. These precompiles enable seamless integration between EVM contracts and Cosmos SDK modules. The EVM communicates with the Cosmos part of the chain through these precompiles - Go code that directly interacts with other module states (e.g., Bank module). Precompiles are special contract addresses that execute native Go code instead of EVM bytecode, enabling seamless integration between EVM and Cosmos SDK modules.

Cosmos SDK Precompiles

There are 5 Cosmos SDK precompiles exposed inside the EVM:

1. Staking Precompile

Interact with the staking module directly from EVM contracts:
  • Delegate tokens: Delegate native tokens to validators
  • Undelegate tokens: Undelegate from validators
  • Redelegate tokens: Move delegation between validators
  • Query delegation information: Get delegation details
Use Cases:
  • Automated staking strategies
  • Liquid staking protocols
  • Validator selection algorithms

2. Distribution Precompile

Manage staking rewards from EVM contracts:
  • Claim rewards: Claim staking rewards
  • Withdraw rewards: Withdraw accumulated rewards
  • Query reward information: Get reward details
Use Cases:
  • Automated reward claiming
  • Reward distribution protocols
  • Staking aggregators

3. Slashing Precompile

Handle slashing operations and re-staking:
  • Re-staking operations: Manage validator re-staking
  • Reward management: Handle slashing-related rewards
  • Validator penalties: Query and handle penalties
Use Cases:
  • Slashing protection protocols
  • Validator health monitoring
  • Risk management systems

4. Governance Precompile

Participate in on-chain governance from EVM contracts:
  • Vote on proposals: Cast votes on governance proposals
  • Create proposals: Submit new governance proposals
  • Query proposal information: Get proposal details and status
Use Cases:
  • Automated governance participation
  • Governance aggregators
  • Proposal creation tools

5. Bank Precompile

Transfer native Cosmos tokens from EVM contracts:
  • Transfer tokens: Send native tokens
  • Query balances: Get token balances
  • Multi-send operations: Batch token transfers
Use Cases:
  • Token bridges
  • Payment protocols
  • Multi-sig wallets

ERC20 Precompiles

Each TokenFactory token has its own ERC20 precompile address, allowing:
  • Control token balance: Manage token balances from EVM
  • Transfer tokens: Transfer TokenFactory tokens
  • Use tokens in EVM contracts: Seamless integration
This enables TokenFactory tokens (created via Cosmos SDK) to be used directly in EVM contracts without wrapping.

Precompile Addresses

Precompile addresses are fixed and documented. The addresses below are examples - actual addresses will be provided in the official documentation.
// Precompile Addresses
address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800;
address constant DISTRIBUTION_PRECOMPILE = 0x0000000000000000000000000000000000000801;
address constant SLASHING_PRECOMPILE = 0x0000000000000000000000000000000000000802;
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000803;
address constant BANK_PRECOMPILE = 0x0000000000000000000000000000000000000804;

Using Precompiles

Basic Pattern

Precompiles are called like regular contract calls:
// Call a precompile
IPrecompileInterface(precompileAddress).functionName(params);

Example: Staking Precompile

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IStakingPrecompile {
    function delegate(address validator, uint256 amount) external returns (bool);
    function undelegate(address validator, uint256 amount) external returns (bool);
    function redelegate(
        address validatorSrc,
        address validatorDst,
        uint256 amount
    ) external returns (bool);
}

contract StakingContract {
    address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800;
    
    function delegateToValidator(address validator, uint256 amount) external {
        IStakingPrecompile(STAKING_PRECOMPILE).delegate(validator, amount);
    }
    
    function undelegateFromValidator(address validator, uint256 amount) external {
        IStakingPrecompile(STAKING_PRECOMPILE).undelegate(validator, amount);
    }
}

Example: Bank Precompile

interface IBankPrecompile {
    function send(
        address to,
        string memory denom,
        uint256 amount
    ) external returns (bool);
    
    function balanceOf(
        address account,
        string memory denom
    ) external view returns (uint256);
}

contract PaymentContract {
    address constant BANK_PRECOMPILE = 0x0000000000000000000000000000000000000804;
    
    function sendNativeToken(
        address to,
        string memory denom,
        uint256 amount
    ) external {
        IBankPrecompile(BANK_PRECOMPILE).send(to, denom, amount);
    }
    
    function getBalance(
        address account,
        string memory denom
    ) external view returns (uint256) {
        return IBankPrecompile(BANK_PRECOMPILE).balanceOf(account, denom);
    }
}

Example: Governance Precompile

interface IGovernancePrecompile {
    function vote(
        uint256 proposalId,
        uint8 option
    ) external returns (bool);
    
    function createProposal(
        string memory title,
        string memory description,
        // ... other proposal parameters
    ) external returns (uint256);
}

contract GovernanceContract {
    address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000803;
    
    function voteOnProposal(uint256 proposalId, uint8 option) external {
        IGovernancePrecompile(GOVERNANCE_PRECOMPILE).vote(proposalId, option);
    }
}

TokenFactory ERC20 Precompiles

TokenFactory tokens automatically get ERC20 precompile addresses:
interface ITokenFactoryERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
}

contract TokenContract {
    // Precompile address for a specific TokenFactory token
    // Address is deterministic based on token denom
    address constant TOKEN_PRECOMPILE = 0x0000000000000000000000000000000000000805;
    
    function transferToken(address to, uint256 amount) external {
        ITokenFactoryERC20(TOKEN_PRECOMPILE).transfer(to, amount);
    }
}

Best Practices

Error Handling

Always check return values from precompiles:
function safeDelegate(address validator, uint256 amount) external {
    bool success = IStakingPrecompile(STAKING_PRECOMPILE).delegate(validator, amount);
    require(success, "Delegation failed");
}

Gas Considerations

Precompiles execute native Go code, which is generally more gas-efficient than contract calls, but still consider:
  • Gas costs for precompile calls
  • Batch operations when possible
  • Optimize for frequently called functions

Security

  • Validate inputs before calling precompiles
  • Use access controls for precompile calls
  • Test precompile interactions thoroughly

Next Steps