Skip to main content
Predeployed contracts (also called preinstalls) are EVM contracts that exist in chain state at a specific address from genesis. Because the address is fixed and known in advance, the same contract can exist at the same address across every chain that includes it, making them useful for infrastructure that needs to be reliably reachable everywhere.

Default Contracts

Cosmos EVM includes five default preinstalls (x/vm/types/preinstall.go):
ContractAddressPurposeDocs
Create20x4e59b44847b379578588920ca78fbf26c0b4956cDeterministic contract deployment using CREATE2EIP-1014
Multicall30xcA11bde05977b3631167028862bE2a173976CA11Batch multiple contract calls in one transactionRepo · Site
Permit20x000000000022D473030F116dDEE9F6B43aC78BA3Signature-based token approvals for any ERC20Repo · Docs
Safe Singleton Factory0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7Deploy Safe multisig wallets at deterministic addressesRepo · Docs
EIP-29350x0000F90827F1C53a10cb7A02335B175320002935Historical block hash storageEIP-2935

Enabling at Genesis

Preinstalls are deployed when the chain first starts, based on the preinstalls array in genesis.json. If the array is empty, no contracts are deployed.

App-level configuration

In your chain’s application code, define which preinstalls to include in NewEVMGenesisState. The evmd reference chain includes all five defaults:
evmd/genesis.go
func NewEVMGenesisState() *evmtypes.GenesisState {
    evmGenState := evmtypes.DefaultGenesisState()
    evmGenState.Params.ActiveStaticPrecompiles = evmtypes.AvailableStaticPrecompiles
    evmGenState.Preinstalls = evmtypes.DefaultPreinstalls
    return evmGenState
}
This function is called by your app’s DefaultGenesis(), which is used when generating genesis state programmatically (e.g. evmd testnet).

Populating genesis.json

evmd init generates a genesis.json with an empty preinstalls array. The app-level preinstall configuration is not automatically written to the genesis file by the init command.
To enable preinstalls on a chain started from a genesis file (including local_node.sh), populate the preinstalls array in genesis.json before starting the node. Each entry requires the contract name, address, and compiled bytecode:
genesis.json
{
  "app_state": {
    "evm": {
      "preinstalls": [
        {
          "name": "Create2",
          "address": "0x4e59b44847b379578588920ca78fbf26c0b4956c",
          "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"
        },
        {
          "name": "Multicall3",
          "address": "0xcA11bde05977b3631167028862bE2a173976CA11",
          "code": "0x..."
        }
      ]
    }
  }
}
The full bytecode for each default preinstall is defined in x/vm/types/preinstall.go.

Adding Contracts After Launch

Governance Proposal

Use MsgRegisterPreinstalls to deploy contracts on a running chain via governance:
proposal.json
{
  "messages": [
    {
      "@type": "/cosmos.evm.vm.v1.MsgRegisterPreinstalls",
      "authority": "<gov module account address>",
      "preinstalls": [
        {
          "name": "Multicall3",
          "address": "0xcA11bde05977b3631167028862bE2a173976CA11",
          "code": "0x..."
        }
      ]
    }
  ],
  "deposit": "10000000stake",
  "title": "Deploy Multicall3",
  "summary": "Deploy Multicall3 to enable batched contract calls"
}
evmd tx gov submit-proposal proposal.json --from mykey --chain-id <chain-id> --gas auto
evmd tx gov vote 1 yes --from mykey

Chain Upgrade Handler

Include preinstalls in a coordinated chain upgrade:
app/upgrades/v2/upgrades.go
func CreateUpgradeHandler(
    mm *module.Manager,
    configurator module.Configurator,
    evmKeeper *evmkeeper.Keeper,
) upgradetypes.UpgradeHandler {
    return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
        if err := evmKeeper.AddPreinstalls(ctx, evmtypes.DefaultPreinstalls); err != nil {
            return nil, err
        }
        return mm.RunMigrations(ctx, configurator, fromVM)
    }
}

Adding Custom Contracts

To deploy a contract beyond the defaults, add it to your preinstalls list:
evmd/genesis.go
customPreinstall := evmtypes.Preinstall{
    Name:    "MyContract",
    Address: "0xYourChosenAddress",
    Code:    "0xCompiledBytecode",
}
evmGenState.Preinstalls = append(evmtypes.DefaultPreinstalls, customPreinstall)
Requirements for a valid preinstall:
  • Valid Ethereum address (0x prefix, 40 hex characters)
  • Must not conflict with existing contracts or precompile addresses (0x1–0x9FF)
  • Non-empty, valid EVM bytecode (hex encoded)

Verification

After the chain starts with preinstalls in genesis.json, confirm the contracts are installed:
# Check contract code is present
evmd query evm code 0x4e59b44847b379578588920ca78fbf26c0b4956c

# Check account exists
evmd query evm account 0x4e59b44847b379578588920ca78fbf26c0b4956c
Both commands should return non-empty results. If code returns null, the preinstall was not included in genesis.json when the chain was initialized.

Troubleshooting

ErrorCauseFix
preinstall already has an account in account keeperAddress already has a contractChoose a different address
preinstall has empty code hashInvalid or empty bytecodeVerify bytecode hex string is valid and non-empty
preinstall address is not a valid hex addressMalformed addressEnsure 0x prefix and 40 hex characters
invalid authorityWrong governance addressUse the correct gov module account address