Skip to main content
packages/abis is the one place off-chain code gets contract interfaces, chain facts and deployed addresses from. Nothing else in the repository hard-codes a chain. It is a workspace package (@launchpad/abis, TypeScript source, no build step) imported by the web app, the indexer, the keeper and the generator scripts.

What the package exports

The ABIs are JSON exported from Foundry’s build output (packages/abis/src/<Name>.json); PoolManager and StateView are Uniswap v4’s, ERC20 is the standard interface. pnpm abis at the repository root (node packages/abis/scripts/export.mjs run from contracts/) regenerates them with forge inspect <Name> abi --json after a contract change. The indexer re-exports them as as const TypeScript in packages/indexer/abis/index.ts (pnpm --filter @launchpad/indexer codegen, also run by postinstall). Package exports: . (the module), ./chains.json, ./deployments/* and ./tokenlist/*.

Deployment files

contracts/script/Deploy.s.sol writes contracts/deployments/<chainId>.json; the deploy scripts copy it to packages/abis/deployments/<chainId>.json, which is the path everything reads. Shape (Deployment):
Mainnet files also carry synthNamePrefix / synthSymbolPrefix (“Windrose” / “w”) and startBlock (the first block of the deployment broadcast, used as the indexer’s default start). deploymentPath(4663) returns deployments/4663.json.

The chain registry: chains.json

One entry per chain the launchpad can run on. CHAIN_LIST is the validated array in file order, CHAINS the same keyed by id, getChain(id) throws with the list of known chains for an unknown id, findChain(id) returns undefined, chainByKey("robinhood") looks up by slug. Validation runs at import time so a typo fails at startup with a readable message. Registered today: Arc testnet 5042002 (arc-testnet), Arc 5042 (arc), Robinhood testnet 46630 (robinhood-testnet), Robinhood Chain 4663 (robinhood). contracts/script/Deploy.s.sol mirrors the dollar, EURC, Permit2, Pyth and Uniswap v4 addresses in its _defaults table because forge scripts cannot read JSON conveniently; keep the two in sync. scripts/chain-env.sh prints an entry as shell variables for the deploy scripts.

Selecting a chain

parseChainId(raw, fallback) turns an environment value into a registered id (empty means fallback, anything else must be a registered positive integer). DEFAULT_CHAIN_ID is read from LAUNCHPAD_CHAIN_ID, then NEXT_PUBLIC_CHAIN_ID, else FALLBACK_CHAIN_ID (46630). Each process reads its own variable:

How addresses are resolved at runtime

Web app. GET /api/deployment?chainId=<id> reads packages/abis/deployments/<id>.json lazily on every request (through the workspace symlink, the relative path or DEPLOYMENTS_DIR), so a file written after the server started shows up and a build passes without one. For the default chain only, NEXT_PUBLIC_FACTORY, NEXT_PUBLIC_ROUTER, NEXT_PUBLIC_REGISTRY, NEXT_PUBLIC_STATE_VIEW, NEXT_PUBLIC_USDC and NEXT_PUBLIC_USDC_SYMBOL are a fallback when the file is absent. GET /api/chains lists every registry chain with whether it is deployed. Both are documented under HTTP endpoints. Indexer. packages/indexer/config/deployment.ts resolves, in priority order: environment overrides (FACTORY_ADDRESS, REGISTRY_ADDRESS, KEEPER_ORACLE_ADDRESS, POOL_MANAGER_ADDRESS, VAULT_ADDRESSES, START_BLOCK_<chainId> then START_BLOCK), then the deployment file (DEPLOYMENTS_FILE or @launchpad/abis/deployments/<chainId>.json, including its startBlock), then zero addresses so codegen and typecheck work before a deployment exists. Vault addresses come from currencies[*].vault, or are discovered from SyntheticCreated when neither source is available. Keeper. DEPLOYMENTS_FILE (default ../abis/deployments/<CHAIN_ID>.json) for the registry and oracle; it refuses to post when registry.oracle() is no longer the file’s keeperOracle.

Generator scripts

Both read the deployment file and contracts/script/Currencies.sol (parsed from source, so they never drift from the deployment) and apply the deployment’s naming prefixes. Token list: pnpm abis:tokenlist (node packages/abis/scripts/tokenlist.mjs [--chain <id>] [--name <list>] [--offline] [--verbose]) writes packages/abis/tokenlist/<key>.tokenlist.json in the Uniswap Token List format: the dollar, EURC where registered and every synthetic, with names, symbols and decimals read from the chain (falling back to the deployment file and Currencies.sol when the RPC is unreachable or --offline). Tags: stablecoin, synthetic, fx. Logos point at TOKEN_LOGO_BASE (default https://windrose.market/tokens/; set it to the deployed origin before publishing). The version follows the token-list rules (major when a token is removed, minor when one is added, patch for metadata) and re-running on an unchanged deployment is a no-op. robinhood.tokenlist.json and arc-testnet.tokenlist.json are committed. Logos: pnpm abis:logos (node packages/abis/scripts/logos.mjs [--chain <id>] [--out apps/web/public/tokens] [--force]) writes one deterministic SVG coin per synthetic (wINR.svg, acINR.svg, …) into apps/web/public/tokens/, each under 4 KB, with hues spread evenly around the wheel so sixty coins stay distinguishable. USDC.svg / EURC.svg / USDG.svg are only written as placeholders when missing; the committed ones are the official marks.

Consuming the package outside the monorepo

The package is not published to npm. Copy packages/abis/src/*.json, chains.json and the deployment file you need, or depend on the repository as a git dependency. Everything is plain JSON plus one TypeScript module with no dependencies, so it also works from a bundler-free Node script: