Skip to content

EVM chain scaffolder #11980

@gomesalexandre

Description

@gomesalexandre

tl;dr

Build a generator script that handles the mechanical ~80% of adding a second-class EVM chain, so Claude (or any agent) only needs to think about the ~20% that genuinely requires research and judgment.

Today, adding a chain touches ~44 integration points across ~35 files. The contract captures every gotcha. But most of those integration points are purely mechanical — append to array, add switch case, clone if-statement, create file from template. No brain needed.

Philosophy: don't use a brain until you need a brain.

the approach: marker-based generation

No AST parsing (jscodeshift/ts-morph). Instead:

  1. ~60 marker comments placed at insertion points across the codebase (// @chain-gen:<KEY>)
  2. A simple generator (scripts/addChain/index.ts) that reads a chain config JSON, finds markers, inserts templated code before them
  3. 6 file templates for new files (chain adapter, plugin, asset gen script, CSP header, tx status util)
  4. Claude handles the 20% — swapper research, stablecoin address lookups, edge case detection, verification

why markers over AST transforms

Markers jscodeshift
Implementation ~200 LOC regex engine ~2000 LOC across 25 codemods
Works on .env/.d.ts yes no
Survives refactors marker moves with code breaks if variable renamed
Fails loudly "marker not found" error silent wrong insertion
Self-documenting markers tell devs "this is extensible" codemods are invisible
Maintenance near zero constant babysitting

chain config schema

Single JSON file per chain with everything the generator needs:

{
  "name": "Bob",
  "camelName": "bob",
  "upperName": "BOB",
  "pascalName": "Bob",
  "evmChainId": 60808,
  "nativeSymbol": "ETH",
  "nativeName": "Ether",
  "nativePrecision": 18,
  "rpcUrl": "https://rpc.gobob.xyz",
  "explorerUrl": "https://explorer.gobob.xyz",
  "color": "#F25D00",
  "viemChainName": "bob",
  "coingeckoPlatform": "bob-network",
  "swappers": { "relay": { "chainId": 60808 } }
}

what the generator handles (~80%)

All mechanical insertions:

  • CAIP constants (chainId, assetId, CHAIN_REFERENCE, ASSET_REFERENCE, VALID_CHAIN_IDS)
  • KnownChainIds enum + EvmChainId union
  • Chain adapter class (file template) + exports
  • Discriminated unions in chain-adapters/types.ts (Account, FeeData, SignTx, etc.)
  • Plugin file (template) + registration in activePlugins.ts
  • Feature flags (preferencesSlice, config.ts, store mock, vite-env.d.ts)
  • .env / .env.development entries
  • Viem client creation + all 3 maps
  • Ethers provider switch case
  • Base asset definition
  • All 5 utility functions (getBaseAsset, chainIdToFeeAssetId, etc.)
  • CSP headers (template + registration)
  • Asset generation script (template + registration)
  • Coingecko adapter (enum, switch cases, parseData)
  • Transaction status utility (template)
  • State migration (bump version, clearAssets entry)
  • HDWallet packages (all 10+ — supports{Chain} pattern)
  • WalletConnect V2 (all 4 touchpoints)
  • PluginProvider, MarketsRow, AssetService feature flag filters
  • Portfolio utils, wallet support hook, EVM account derivation
  • SECOND_CLASS_CHAINS array, popular assets, opportunities mappings
  • Coingecko supported chain IDs

what claude handles (~20%)

  • Swapper research: check Relay, Across, Portals, Zerion, Yield.xyz docs for chain support
  • Related asset index: look up native USDC/USDT/DAI addresses, manual mappings
  • Edge cases: ERC20 native duplicate blacklisting, market service test counts, icon URL validation
  • Data generation: run yarn generate:chain
  • Verification: lint, type-check, runtime testing

the workflow end-to-end

1. Fill chain-config.json (Claude can help research fields)
2. yarn ts-node scripts/addChain/index.ts configs/<chain>.json  (~5 seconds)
3. Claude handles research items (swappers, related assets, edge cases)
4. yarn generate:chain eip155:<chainId>
5. yarn lint --fix && yarn type-check
6. Runtime verification

one contract, two modes

The existing contract stays as the single source of truth for both building AND reviewing chain PRs. Each item gets annotated:

1. **CAIP Constants** `[auto]` - packages/caip/src/constants.ts
   - <chain>AssetId, <chain>ChainId, ...

27. **Relay Swapper** `[research]` - packages/swapper/src/swappers/RelaySwapper/constant.ts
    - Check https://relay.link for supported chains

Then:

  • Build mode (/chain-integration skill): skips [auto] items (generator handles them), only walks through [research] items
  • Review mode (PR review skill): reads ALL items regardless of tag, does full gap analysis against the PR diff — if an [auto] item is missing, the generator wasn't used or has a bug, either way the review catches it

The contract never shrinks. The tags just tell the build skill "don't waste brain on this, the generator already did it."

implementation order

  1. Add markers — place ~60 // @chain-gen:* comments across existing files (purely additive, zero behavior change)
  2. Build generator — schema, templates, snippet registry, engine, report
  3. Test roundtrip — delete an existing chain (Bob), re-generate, diff against original
  4. Annotate contract — add [auto]/[research] tags to every item
  5. Update /chain-integration skill — run generator first, then research items only
  6. CI integration — marker verification job (fails if any marker deleted during refactors)

references

  • Current contract: .claude/contracts/second-class-evm-chain.md
  • Full plan with detailed marker placement map: .claude/plans/atomic-wibbling-stream.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions