> ## Documentation Index
> Fetch the complete documentation index at: https://cosmos-docs-sync-security-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Precompile Configuration

> Choose which precompiles are active on your chain and add custom ones.

[Precompiles](/evm/latest/documentation/smart-contracts/precompiles/overview) are smart contract interfaces at fixed addresses where the implementation runs as native Go code. Cosmos EVM ships with precompiles for staking, governance, IBC, and more. As a chain builder you control which ones are active and can add your own. For more information and to see the full list of available precompiles, see the [precompiles overview](/evm/latest/documentation/smart-contracts/precompiles/overview).

## Enabling Precompiles

Precompiles are enabled via the `active_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](/evm/latest/documentation/smart-contracts/precompiles/overview).

1. Wire precompiles into the EVM keeper in `app.go` using `.WithStaticPrecompiles()`. The standard way is to pass `precompiletypes.DefaultStaticPrecompiles(...)`, which includes all built-in precompiles:

```go title="evmd/app.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
).WithStaticPrecompiles(
    precompiletypes.DefaultStaticPrecompiles(
        *app.StakingKeeper,
        app.DistrKeeper,
        app.PreciseBankKeeper,
        &app.Erc20Keeper,
        &app.TransferKeeper,
        app.IBCKeeper.ChannelKeeper,
        app.IBCKeeper.ClientKeeper,
        app.GovKeeper,
        app.SlashingKeeper,
        appCodec,
    ),
)
```

If you want a custom set, replace `DefaultStaticPrecompiles` with your own builder chain (see [Adding a Custom Precompile](#adding-a-custom-precompile) below).

2. Set the active precompiles in your genesis configuration ([`evmd/genesis.go`](https://github.com/cosmos/evm/blob/main/evmd/genesis.go)):

```go theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
func NewEVMGenesisState() *evmtypes.GenesisState {
    evmGenState := evmtypes.DefaultGenesisState()

    // Enable all available precompiles
    evmGenState.Params.ActiveStaticPrecompiles = evmtypes.AvailableStaticPrecompiles
    evmGenState.Preinstalls = evmtypes.DefaultPreinstalls

    return evmGenState
}
```

To enable only a specific subset, pass the addresses explicitly. Addresses must be in sorted order (see [Adding a Custom Precompile](#adding-a-custom-precompile) below):

```go theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
evmGenState.Params.ActiveStaticPrecompiles = []string{
    evmtypes.StakingPrecompileAddress,      // 0x0000000000000000000000000000000000000800
    evmtypes.DistributionPrecompileAddress, // 0x0000000000000000000000000000000000000801
    evmtypes.BankPrecompileAddress,         // 0x0000000000000000000000000000000000000804
}
```

The full list of available addresses is defined in [`x/vm/types/precompiles.go`](https://github.com/cosmos/evm/blob/main/x/vm/types/precompiles.go). See the [precompiles overview](/evm/latest/documentation/smart-contracts/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 stateful `DenomSupply` 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 directory `precompiles/denomsupply/` with two files:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
mkdir -p precompiles/denomsupply
```

`precompiles/denomsupply/abi.json` — the Solidity ABI:

```json title="precompiles/denomsupply/abi.json" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
[
  {
    "inputs": [{"internalType": "string", "name": "denom", "type": "string"}],
    "name": "supplyOf",
    "outputs": [{"internalType": "uint256", "name": "amount", "type": "uint256"}],
    "stateMutability": "view",
    "type": "function"
  }
]
```

`precompiles/denomsupply/denomsupply.go` — the implementation:

```go title="precompiles/denomsupply/denomsupply.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
package denomsupply

import (
    "bytes"
    _ "embed"
    "fmt"

    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/vm"

    cmn "github.com/cosmos/evm/precompiles/common"
    evmtypes "github.com/cosmos/evm/x/vm/types"

    storetypes "cosmossdk.io/store/types"
    sdk "github.com/cosmos/cosmos-sdk/types"
)

var _ vm.PrecompiledContract = &Precompile{}

var (
    //go:embed abi.json
    f   []byte
    ABI abi.ABI
)

func init() {
    var err error
    ABI, err = abi.JSON(bytes.NewReader(f))
    if err != nil {
        panic(err)
    }
}

// Precompile queries the total supply of a Cosmos denomination from the bank module.
type Precompile struct {
    cmn.Precompile
    bankKeeper cmn.BankKeeper
}

func NewPrecompile(bankKeeper cmn.BankKeeper) *Precompile {
    return &Precompile{
        Precompile: cmn.Precompile{
            KvGasConfig:          storetypes.GasConfig{},
            TransientKVGasConfig: storetypes.GasConfig{},
            ContractAddress:      common.HexToAddress(evmtypes.DenomSupplyPrecompileAddress),
        },
        bankKeeper: bankKeeper,
    }
}

func (p Precompile) RequiredGas(_ []byte) uint64 {
    return 3_000
}

// Run executes the precompile inside the Cosmos EVM context.
// RunNativeAction bridges the EVM execution environment to the Cosmos SDK,
// providing an sdk.Context with access to all module state.
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) {
    return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) {
        method, args, err := cmn.SetupABI(ABI, contract, readonly, p.IsTransaction)
        if err != nil {
            return nil, err
        }

        switch method.Name {
        case "supplyOf":
            denom, ok := args[0].(string)
            if !ok {
                return nil, fmt.Errorf("invalid argument: expected string")
            }
            coin := p.bankKeeper.GetSupply(ctx, denom)
            return method.Outputs.Pack(coin.Amount.BigInt())
        }

        return nil, fmt.Errorf("unknown method: %s", method.Name)
    })
}

// IsTransaction returns false because supplyOf is a read-only query.
func (Precompile) IsTransaction(_ *abi.Method) bool {
    return false
}
```

The struct embeds `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

In [`x/vm/types/precompiles.go`](https://github.com/cosmos/evm/blob/main/x/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):

```go title="x/vm/types/precompiles.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
	DenomSupplyPrecompileAddress   = "0x0000000000000000000000000000000000000809"
```

Append it to the `AvailableStaticPrecompiles` slice (inserted before the closing `}` at line 35, shifted +1 by the previous insert):

```go title="x/vm/types/precompiles.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
	DenomSupplyPrecompileAddress, // appended in sorted order: 0x...0807 < 0x...0809
```

### 3. Add a builder method

In [`precompiles/types/static_precompiles.go`](https://github.com/cosmos/evm/blob/main/precompiles/types/static_precompiles.go), add the import for the new package (inserted before `ics02precompile` at line 16, between `govprecompile` and `ics02precompile`):

```go title="precompiles/types/static_precompiles.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
	denomsupplyprecompile "github.com/cosmos/evm/precompiles/denomsupply"
```

Then add the `With` method at the very end of the file. Pass any keepers your precompile needs as parameters:

```go title="precompiles/types/static_precompiles.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}

func (s StaticPrecompiles) WithDenomSupplyPrecompile(bankKeeper cmn.BankKeeper) StaticPrecompiles {
	denomSupplyPrecompile := denomsupplyprecompile.NewPrecompile(bankKeeper)
	s[denomSupplyPrecompile.Address()] = denomSupplyPrecompile
	return s
}
```

### 4. Wire it into the app

In [`precompiles/types/defaults.go`](https://github.com/cosmos/evm/blob/main/precompiles/types/defaults.go), add your method to the builder chain by replacing line 89 (`WithSlashingPrecompile`). The `bankKeeper` is already a parameter of `DefaultStaticPrecompiles`:

```go title="precompiles/types/defaults.go" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
		WithSlashingPrecompile(slashingKeeper, bankKeeper, opts...).
		WithDenomSupplyPrecompile(bankKeeper)
```

### 5. Activate at genesis

Because `evmd/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:

```bash title="local_node.sh" theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
  jq '.app_state["evm"]["params"]["active_static_precompiles"] +=
    ["0x0000000000000000000000000000000000000809"]' \
    "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
```

### 6. Build and verify

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
make install
```

Start a local chain in the background:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
bash local_node.sh -y --no-install
```

Once the chain is running, call the precompile and get a decoded result in one step:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
cast call 0x0000000000000000000000000000000000000809 \
  "supplyOf(string)(uint256)" "atest" \
  --rpc-url http://localhost:8545
# 100025807224055573593873019 [1e26]
```

When successful, you should see `100025807224055573593873019` in the output.
