-
Notifications
You must be signed in to change notification settings - Fork 202
Description
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:
- ~60 marker comments placed at insertion points across the codebase (
// @chain-gen:<KEY>) - A simple generator (
scripts/addChain/index.ts) that reads a chain config JSON, finds markers, inserts templated code before them - 6 file templates for new files (chain adapter, plugin, asset gen script, CSP header, tx status util)
- 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 chainsThen:
- Build mode (
/chain-integrationskill): 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
- Add markers — place ~60
// @chain-gen:*comments across existing files (purely additive, zero behavior change) - Build generator — schema, templates, snippet registry, engine, report
- Test roundtrip — delete an existing chain (Bob), re-generate, diff against original
- Annotate contract — add
[auto]/[research]tags to every item - Update
/chain-integrationskill — run generator first, then research items only - 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
Labels
Type
Projects
Status