How Precompiles Work
Precompiles are special contracts that exist at the protocol level rather than as deployed bytecode on the blockchain. They execute native code directly within the node software, offering significant performance advantages over regular smart contracts while maintaining compatibility with the EVM interface.Architecture
Precompiles operate through a unique architecture:- Native Implementation: Unlike regular smart contracts that execute bytecode through the EVM interpreter, precompiles run optimized native code directly within the blockchain node
- Fixed Addresses: Each precompile is assigned a specific address in the reserved range (typically
0x00...00
to0x00...FF
for standard precompiles, with extended ranges for custom implementations) - Gas Metering: Precompiles use predetermined gas costs for operations, often much lower than equivalent EVM bytecode execution
- State Access: They have direct access to the underlying blockchain state through native modules, bypassing EVM state management overhead
Building and Implementing Precompiles
Creating custom precompiles involves several key steps:- Define the Interface: Create a Solidity interface that defines the precompile’s functions and events
- Implement Native Logic: Write the actual implementation in the node’s native language (typically Go for Cosmos chains)
- Register the Precompile: Map the implementation to a specific address in the EVM configuration
- Gas Configuration: Define appropriate gas costs for each operation based on computational complexity
- Input parsing and validation from EVM calldata
- State transitions through the native module system
- Result encoding back to EVM-compatible formats
- Error handling and reversion logic
Implementation Patterns
Based on the Cosmos EVM precompile architecture, several critical patterns must be followed when implementing precompiles:1. The Run/run Wrapper Pattern
Every precompile implements a publicRun
method that wraps a private run
method. This pattern provides consistent error handling and return value formatting:
2. Native Balance Handler
Precompiles that modify native token balances must use the balance handler to track changes properly. The handler monitors bank module events and synchronizes them with the EVM state:- Records the event count before operations
- Processes
CoinSpent
andCoinReceived
events after operations - Updates the StateDB with
AddBalance
andSubBalance
calls - Handles fractional balance changes for precise accounting
- Bypasses blocked addresses to prevent authorization errors
3. Required Structure
Every precompile must embed the commonPrecompile
struct and implement these components:
4. Gas Management
Precompiles use a two-phase gas management approach:5. State Management
Precompiles must properly manage state transitions:Testing Precompiles
The Testing Challenge
A significant challenge when working with precompiles is that their code doesn’t exist as deployable bytecode. Traditional development tools like Foundry or Hardhat cannot directly access precompile implementations since they simulate the EVM locally without the underlying node infrastructure. When these tools encounter a call to a precompile address, they find no deployed code and the call fails.Using Foundry’s Etch Cheatcode
Foundry provides a powerful workaround through itsvm.etch
cheatcode, which allows you to inject bytecode at any address during testing. This enables simulation of precompile behavior by deploying mock implementations at the precompile addresses.
Here’s how to use etch
effectively:
- Test smart contracts that interact with precompiles
- Simulate various precompile responses and edge cases
- Develop and debug locally without a full node setup
- Maintain consistent testing workflows with other smart contract development
Available Precompiles
Precompile | Address | Purpose | Reference |
---|---|---|---|
Bank | 0x0000000000000000000000000000000000000804 | ERC20-style access to native Cosmos SDK tokens | Details |
Bech32 | 0x0000000000000000000000000000000000000400 | Address format conversion between Ethereum hex and Cosmos bech32 | Details |
Staking | 0x0000000000000000000000000000000000000800 | Validator operations, delegation, and staking rewards | Details |
Distribution | 0x0000000000000000000000000000000000000801 | Staking rewards and community pool management | Details |
ERC20 | Dynamic per token | Standard ERC20 functionality for native Cosmos tokens | Details |
Governance | 0x0000000000000000000000000000000000000805 | On-chain governance proposals and voting | Details |
ICS20 | 0x0000000000000000000000000000000000000802 | Cross-chain token transfers via IBC | Details |
WERC20 | Dynamic per token | Wrapped native token functionality | Details |
Slashing | 0x0000000000000000000000000000000000000806 | Validator slashing and jail management | Details |
P256 | 0x0000000000000000000000000000000000000100 | P-256 elliptic curve cryptographic operations | Details |