Enabling Precompiles
Precompiles are enabled via theactive_static_precompiles parameter in the vm module. Only addresses listed here are callable at runtime. For the full list of built-in precompiles and their addresses, see the precompiles overview.
- Wire precompiles into the EVM keeper in
app.gousing.WithStaticPrecompiles(). The standard way is to passprecompiletypes.DefaultStaticPrecompiles(...), which includes all built-in precompiles:
evmd/app.go
DefaultStaticPrecompiles with your own builder chain (see Adding a Custom Precompile below).
- Set the active precompiles in your genesis configuration (
evmd/genesis.go):
x/vm/types/precompiles.go. See the precompiles overview for more information.
Already-registered precompiles can also be enabled or disabled after launch via a governance parameter change proposal targeting the vm module’s active_static_precompiles param. Adding a genuinely new custom precompile requires a chain upgrade, since the implementation lives in the Go binary.
Adding a Custom Precompile
The following example adds a statefulDenomSupply precompile with a single supplyOf method that reads total token supply directly from the Cosmos bank module. This demonstrates the core pattern for basic precompiles: injecting a Cosmos SDK keeper and using RunNativeAction to access live chain state from an EVM call.
1. Create the precompile package
Create a directoryprecompiles/denomsupply/ with two files:
precompiles/denomsupply/abi.json — the Solidity ABI:
precompiles/denomsupply/abi.json
precompiles/denomsupply/denomsupply.go — the implementation:
precompiles/denomsupply/denomsupply.go
cmn.Precompile rather than handling context directly. RunNativeAction sets up the SDK context, manages gas metering, and handles snapshot/revert so that precompile calls participate correctly in EVM transaction atomicity. Inside the closure, p.bankKeeper provides access to the bank module’s state.
2. Register the address
Inx/vm/types/precompiles.go, add a constant before the closing ) of the const block (line 17) and append it to AvailableStaticPrecompiles before its closing } (line 35, shifted +1 by the constant insert). Addresses must be in sorted order.
Add the constant (inserted before the closing ) at line 17):
x/vm/types/precompiles.go
AvailableStaticPrecompiles slice (inserted before the closing } at line 35, shifted +1 by the previous insert):
x/vm/types/precompiles.go
3. Add a builder method
Inprecompiles/types/static_precompiles.go, add the import for the new package (inserted before ics02precompile at line 16, between govprecompile and ics02precompile):
precompiles/types/static_precompiles.go
With method at the very end of the file. Pass any keepers your precompile needs as parameters:
precompiles/types/static_precompiles.go
4. Wire it into the app
Inprecompiles/types/defaults.go, add your method to the builder chain by replacing line 89 (WithSlashingPrecompile). The bankKeeper is already a parameter of DefaultStaticPrecompiles:
precompiles/types/defaults.go
5. Activate at genesis
Becauseevmd/genesis.go already uses evmtypes.AvailableStaticPrecompiles, adding your address to that slice in Step 2 is sufficient — no change to genesis.go is required.
If you use local_node.sh for local development, that script hardcodes the precompile list via a jq command and does not read from AvailableStaticPrecompiles at runtime. Insert the following before line 244 of local_node.sh (the blank line after the active_static_precompiles jq command at line 243) to append your address:
local_node.sh
6. Build and verify
100025807224055573593873019 in the output.