Skip to content
starskiff

Custom Chains

Wrap any Cosmos SDK binary with cosmosBase / cosmosEvmBase

Any Cosmos SDK binary that follows the standard initgenesisstart CLI shape works with starskiff. Instance definitions are thin wrappers: set the binary name and chain defaults, delegate the rest.

Minimal instance

import { Instance, cosmosBase, type CosmosChainParameters } from 'starskiff';
 
export type MychaindParameters = CosmosChainParameters & {
  binary?: string;
};
 
export const mychaind = Instance.define((parameters?: MychaindParameters) => {
  const { binary = 'mychaind', ...rest } = parameters || {};
  return cosmosBase({ binary, name: 'mychaind', ...rest });
});
 
const instance = mychaind({ chainId: 'my-1', denom: 'umych' });

cosmosBase handles the full boot flow: init → genesis denom patching → key creation + account funding → gentx / collect-gentxs → config.toml/app.toml port patching → start → health-polling until the first block.

Patching genesis

Chain-specific genesis tweaks go through the patchGenesis hook, applied after starskiff's default denom patching:

return cosmosBase({
  binary, name: 'mychaind', ...rest,
  patchGenesis: (genesis) => {
    genesis.app_state.gov.params.voting_period = '5s';
    return genesis;
  },
});

Extra config patches and start flags are available for the odd chain that needs them:

HookApplies to
patchGenesisgenesis.json (after denom patching)
extraAppTomlapp.toml ('section.key': 'value')
extraConfigTomlconfig.toml
extraStartArgsappended to the start command
extraReadinessCheckANDed with the first-block health check

Runtime inputs

Custom chain definitions can attach environment variables and read-only files to every lifecycle command with runtime. Environment settings apply to both local binaries and containers; mounts apply only when image is used.

return cosmosBase({
  binary,
  name: 'mychaind',
  image,
  runtime: {
    environment: { MYCHAIN_CONFIG_DIR: image ? '/starskiff/config' : configDirectory },
    mounts: image
      ? [{ source: configDirectory, target: '/starskiff/config', readOnly: true }]
      : undefined,
  },
});

Keep chain-specific details on the wrapper interface. For example, accept a configDirectory option and translate it into runtime internally rather than asking callers for environment-variable names or container paths.

EVM chains

For cosmos-evm chains, cosmosEvmBase extends the flow with a JSON-RPC port (evmPort, patched into app.toml and health-checked on start), ethermint relayer hints for Hermes, an activeStaticPrecompiles genesis patch, and an optional validated evmChainId passed to the node at start:

import { Instance, cosmosEvmBase, type CosmosEvmChainParameters } from 'starskiff';
 
export const myevmd = Instance.define((parameters?: CosmosEvmChainParameters) => {
  return cosmosEvmBase({
    binary: 'myevmd',
    name: 'myevmd',
    evmChainId: 12345,
    denom: 'atoken', // 18 decimals → bump validator amounts:
    validatorBalance: '100000000000000000000000', // 1e23
    validatorStake: '10000000000000000000000', // 1e22
    ...parameters,
  });
});

18-decimal denoms need large validator amounts because the SDK's power reduction is denom-scaled — see the shipped evmd definition for a reference implementation (it also shows denom-metadata and precompile patching for chains whose init writes incomplete genesis defaults).