Add Warp Route ID

SkillCloud & infra

Post-registry-merge steps for a new warp route deployment. Adds the warp route ID to warpIds.ts, updates .registryrc to latest registry commit, runs update-agent-config, then guides the user through warp monitor deployment and PR creation.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Add Warp Route ID skill

What this skill tells your AI

The instructions your AI receives, as published by hyperlane-xyz/hyperlane-monorepo in .claude/skills/warp-deploy-register-route/SKILL.md and read by ahel’s review.

You are completing the post-registry-merge steps for a new warp route deployment.

Run Log (mandatory)

Maintain the durable run log per /warp-run-log — that skill owns the storage contract (Linear-document-by-title primary, single-writer discipline, local-file fallback), the machine-row + prose entry shape, and the surface-the-URL-as-proof hard gate. Key the document by the ticket ID (or, for a route-ID-only batch with no ticket, the primary warp route ID). Use warp-deploy-register-route as the skill name in each prose entry, and do not report this skill complete until the run-log URL has been surfaced.

Log at least: (a) skill entry with the warp route ID(s) being registered, (b) the warpIds.ts enum edit, (c) the .registryrc bump commit, (d) the pnpm agent-configs run, (e) the warp monitor / rebalancer deploy result, (f) the monorepo PR URL, (g) skill exit (success or bail-out). Log smooth steps too — success data grounds the retrospective as much as failure data.

Input

The user provides one or more warp route IDs in the format TOKEN/chain (stable ID — just the primary new/synthetic chain), and/or one or more Linear ticket URLs. Multiple routes can be batched into a single PR.

If Linear ticket URL(s) are provided, fetch each ticket to extract the warp route ID and route details. Look for fields like "Route Type", "Connected Chains", and notes about ownership/ICA.

If no warp route ID was provided, ask the user for it now.

When multiple routes are provided, process Steps 1–5 for each route independently (each gets its own enum entry and warp monitor), then create a single combined PR in Step 6 that covers all routes.


Detecting Route Type: Simple vs. Multi-Collateral

Before proceeding, classify the route:

Simple route — one or two chains, no rebalancing, no ICA ownership:

  • Proceed with Steps 1–6 as written below.
  • Skip Step 2b entirely.

Multi-collateral route with rebalancing — multiple collateral chains + one synthetic, CCTP rebalancing bridges, ICA-based ownership:

  • Identifiers: 3+ chains, or Linear ticket says "ICA on all chains", or registry config has allowedRebalancers/allowedRebalancingBridges.
  • Must complete Step 2b (configGetter) in addition to Steps 1–6.


Step 1: Derive the Enum Key Name

Convert the warp route ID to a PascalCase TypeScript enum key.

Pattern (look at existing entries in warpIds.ts for guidance):

  • Parse the warp route ID: TOKEN/chain (stable format — just the primary new/synthetic chain)
  • Combine chain (PascalCase) + Token: e.g. USDS/igraIgraUSDS
  • For tokens with special casing already used in the file (e.g. stHYPER, Re7LRT), preserve it
  • Check existing entries in typescript/infra/config/environments/mainnet3/warp/warpIds.ts to find the closest analogous pattern

Examples from the file:

  • IgraUSDC = 'USDC/igra' — single collateral: <NewChain><TOKEN>
  • EthereumIgraUSDS = 'USDS/ethereum-igra' — multi collateral: <CollateralChain><NewChain><TOKEN>
  • ArbitrumTIA = 'TIA/arbitrum' — older single-chain format, still valid for existing routes

For USDS/igra, the key would be IgraUSDS. For USDS/ethereum-igra, the key would be EthereumIgraUSDS.

Confirm the derived key name makes sense before proceeding.


Step 2: Add Entry to warpIds.ts

File: typescript/infra/config/environments/mainnet3/warp/warpIds.ts

  1. Read the current file
  2. Add the new enum entry in an appropriate location (group with related routes if there's a logical section; otherwise append before the closing })
  3. Use the format: EnumKeyName = 'TOKEN/chains',

Example additions:

  IgraUSDC = 'USDC/igra',         // single collateral
  EthereumIgraUSDS = 'USDS/ethereum-igra',  // multi collateral

After editing, show the user the added line and confirm the file looks correct.


Step 2b: ConfigGetter (Multi-Collateral Routes Only)

Skip this step for simple routes.

Multi-collateral routes with ICA ownership and CCTP rebalancing require a configGetter in addition to the warpIds.ts entry. This enables warp apply and ownership management.

Files to create/modify:

1. Uncomment warpFees ICA entry (if commented out)

File: typescript/infra/config/environments/mainnet3/governance/ica/warpFees.ts

Check if the synthetic chain is commented out in the warpFees ICA map. If so, uncomment it. The warpFees ICA address is the fee owner for the synthetic token's routing fee contract.

Example — for USDC/igra, uncomment:

igra: '0x42cb788529463B1F41de9E3cd3d2906930aCd32F',

2. Create the configGetter

File: typescript/infra/config/environments/mainnet3/warp/configGetters/get<SyntheticChain><TOKEN>WarpConfig.ts

Follow the pattern from getElectroneumUSDCWarpConfig.ts (simplest multi-collateral example) or getEclipseUSDCWarpConfig.ts (advanced with fees + proxy admins).

Key structure:

  • ownersByChain: hardcode from the deploy YAML's owner fields (these are ICA/Safe addresses already set during deployment)
  • collateralChains: all non-synthetic chains
  • rebalancingConfigByChain: call getUSDCRebalancingBridgesConfigFor(collateralChains, [WarpRouteIds.MainnetCCTPV2Standard, WarpRouteIds.MainnetCCTPV2Fast])
  • Each collateral chain: getRebalancingUSDCConfigForChain(chain, routerConfig, ownersByChain, rebalancingConfigByChain)
  • Synthetic chain: getSyntheticTokenConfigForChain(...) + add tokenFee: getFixedRoutingFeeConfig(getWarpFeeOwner(syntheticChain), collateralChains, bps) if the deploy YAML shows a tokenFee

Also export get<Name>StrategyConfig for ICA-based warp apply:

  • ORIGIN_CHAIN = 'ethereum'
  • safeAddress = ownersByChain.ethereum (the ethereum Safe that controls all ICAs)
  • All non-ethereum chains get TxSubmitterType.INTERCHAIN_ACCOUNT submitters routing through the ethereum Safe
export const get<Name>StrategyConfig = (): ChainSubmissionStrategy => {
  const safeAddress = ownersByChain[ORIGIN_CHAIN];
  const originSafeSubmitter = { type: TxSubmitterType.GNOSIS_SAFE, chain: ORIGIN_CHAIN, safeAddress };
  const chainAddress = getChainAddresses();
  const originInterchainAccountRouter = chainAddress[ORIGIN_CHAIN].interchainAccountRouter;
  assert(originInterchainAccountRouter, ...);
  const icaChains = [...collateralChains, syntheticChain].filter(c => c !== ORIGIN_CHAIN);
  const icaStrategies = icaChains.map(chain => [chain, { submitter: {
    type: TxSubmitterType.INTERCHAIN_ACCOUNT, chain: ORIGIN_CHAIN, destinationChain: chain,
    owner: safeAddress, originInterchainAccountRouter, internalSubmitter: originSafeSubmitter,
  }}]);
  return Object.fromEntries([[ORIGIN_CHAIN, { submitter: originSafeSubmitter }], ...icaStrategies]);
};

3. Register in config/warp.ts

File: typescript/infra/config/warp.ts

Add the import and register in both maps:

import { get<Name>StrategyConfig, get<Name>WarpConfig } from './environments/mainnet3/warp/configGetters/get<Name>WarpConfig.js';

// in warpConfigGetterMap:
[WarpRouteIds.<EnumKey>]: get<Name>WarpConfig,

// in strategyConfigGetterMap:
[WarpRouteIds.<EnumKey>]: get<Name>StrategyConfig,

After writing, run pnpm -C typescript/infra tsc --noEmit --skipLibCheck to verify no type errors.

4. Create rebalancer config

File: typescript/infra/config/environments/mainnet3/rebalancer/<TOKEN>/<label>-config.yaml

Where <label> is the part of the warp route ID after the / (e.g. USDC/igraigra-config.yaml).

Use the weighted strategy for most routes. Weights come from the Linear ticket notes (e.g. "35% ethereum, 20% arb, ..."). Bridge addresses are the CCTP V2 Standard bridge contracts per chain — find these in the allowedRebalancingBridges field of the deploy YAML (first bridge listed per destination pair).

warpRouteId: TOKEN/label

strategy:
  rebalanceStrategy: weighted
  chains:
    ethereum:
      weighted:
        weight: 35 # from Linear ticket weights
        tolerance: 5
      bridgeLockTime: 1800 # 30 mins for CCTP
      bridgeMinAcceptedAmount: 1000
      bridge: '0x...' # CCTP V2 Standard bridge on this chain

    arbitrum:
      weighted:
        weight: 20
        tolerance: 5
      bridgeLockTime: 1800
      bridgeMinAcceptedAmount: 1000
      bridge: '0x...'
    # ... repeat for all collateral chains

Common CCTP V2 Standard bridge addresses (verify against deploy YAML):

  • ethereum: 0x8c8D831E1e879604b4B304a2c951B8AEe3aB3a23
  • arbitrum: 0x4c19c653a8419A475d9B6735511cB81C15b8d9b2
  • base, optimism, polygon, avalanche: 0x33e94B6D2ae697c16a750dB7c3d9443622C4405a

Step 3: Update .registryrc to Latest Registry Commit

File: .registryrc (repo root)

Get the latest commit hash from the hyperlane-registry main branch:

git ls-remote https://github.com/hyperlane-xyz/hyperlane-registry.git HEAD | awk '{print $1}'

Update .registryrc with the new commit hash (single line, no trailing newline issues — match the current format exactly).

Show the user the old and new commit hash before writing.


Step 3b: Verify Local Registry Is Up To Date

Before running update-agent-config, check that the local hyperlane-registry clone is present and on the latest main commit. The registry must be cloned next to the monorepo (i.e. ../hyperlane-registry relative to the monorepo root).

MONOREPO_DIR=$(pwd)  # should be the hyperlane-monorepo root
REGISTRY_PATH="$(dirname $MONOREPO_DIR)/hyperlane-registry"

if [ ! -d "$REGISTRY_PATH" ]; then
  echo "❌ Local registry not found at $REGISTRY_PATH"
  echo "Please clone it: git clone https://github.com/hyperlane-xyz/hyperlane-registry.git $REGISTRY_PATH"
  exit 1
fi

LOCAL_COMMIT=$(git -C "$REGISTRY_PATH" rev-parse HEAD)
REMOTE_COMMIT=$(git ls-remote https://github.com/hyperlane-xyz/hyperlane-registry.git HEAD | awk '{print $1}')

echo "Local registry HEAD:  $LOCAL_COMMIT"
echo "Remote registry HEAD: $REMOTE_COMMIT"

if [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
  echo "❌ Local registry is not up to date."
  echo "Run \`git -C $REGISTRY_PATH pull\` and retry. Aborting to avoid stale agent config."
  exit 1
fi

echo "✅ Local registry is up to date."

If the local registry is behind:

  • The check above exit 1s — surface the error to the user and stop. They must run git -C <path> pull before retrying.

Step 4: Run agent-configs (repo root, regenerates BOTH mainnet3 and testnet4)

From the monorepo root, run:

pnpm agent-configs

This regenerates agent configuration files based on the updated registry — both mainnet_config.json and testnet_config.json. Use this instead of pnpm -C typescript/infra run update-agent-config:mainnet3, which only touches mainnet3 and lets testnet4 drift (the regression behind PR #8846).

  • Stream/show the output to the user
  • If it fails, show the error and stop — do not proceed until the user resolves it
  • On success, confirm it completed

Step 5: Deploy Warp Monitor

Run directly from the typescript/infra directory (requires helm and kubectl). Pass --registry-commit and --yes to run non-interactively:

pnpm tsx ./scripts/warp-routes/deploy-warp-monitor.ts -e mainnet3 --warpRouteId <WARP_ROUTE_ID> --registry-commit <REGISTRY_COMMIT> --yes

Use the registry commit hash from Step 3 as <REGISTRY_COMMIT>.

  • Show the full output to the user
  • If it fails, surface the error and stop

Step 5b: Check Warp Monitor Pod Status

Run directly from the typescript/infra directory:

pnpm tsx ./scripts/warp-routes/status.ts --warpRouteId <WARP_ROUTE_ID> -e mainnet3

Run from the typescript/infra directory.

Analyze the output yourself:

  • Look for the pod status (e.g. Running, Pending, CrashLoopBackOff, Error)
  • Check that the warp route ID appears in the output and is recognized
  • Check for any error messages or missing configuration
  • A healthy deployment shows the pod in Running state with no errors

The pod may take 1-2 minutes to reach Running state after deploy. If the status shows Pending, ContainerCreating, or CreateContainerConfigError on the first check, wait 60 seconds and re-run the status check before treating it as a failure.

If still not running after 2 minutes, diagnose with kubectl describe pod <pod-name> -n mainnet3 and surface the events to the user.

If healthy, summarize the status and proceed to Step 6. If not, explain what's wrong and wait for the user to resolve it.


Step 6: Create PR

Create the monorepo PR directly using gh pr create. First check out a branch:

git checkout -b <your-name>/add-warp-route-<token>-<chains>

Then stage and commit only the files this skill modifies — do NOT git add whole directories, as that picks up unrelated stale edits.

For a simple route:

git add typescript/infra/config/environments/mainnet3/warp/warpIds.ts
git add .registryrc
git add rust/main/app-contexts/mainnet_config.json
git add rust/main/config/mainnet_config.json
git add rust/main/config/testnet_config.json
git commit -m "feat: add <WARP_ROUTE_ID> warp route"
git push -u origin HEAD

For a multi-collateral / config-getter route, also add the specific files you created/modified:

git add typescript/infra/config/environments/mainnet3/warp/configGetters/get<Name>WarpConfig.ts
git add typescript/infra/config/warp.ts
git add typescript/infra/config/environments/mainnet3/governance/ica/warpFees.ts        # only if you uncommented an entry
git add typescript/infra/config/environments/mainnet3/rebalancer/<TOKEN>/<label>-config.yaml

Run git status before commit and visually confirm the staged set matches the intended changes; abort and unstage any unexpected files.

Then open the PR:

gh pr create \
  --base main \
  --title "feat: add <WARP_ROUTE_ID> warp route" \
  --body "$(cat <<'EOF'
## Summary

Adds the `<WARP_ROUTE_ID>` warp route to the monorepo.

| Field | Value |
| ----- | ----- |
| **Linear** | <linear-issue-url> |
| **Warp route ID** | `<WARP_ROUTE_ID>` |
| **Warp monitor** | [Grafana](https://abacusworks.grafana.net/d/ddz6ma94rnzswc/warp-routes?orgId=1&var-warp_route_id=<URL-encoded-warp-route-id>) |

## Changes

- `typescript/infra/config/environments/mainnet3/warp/warpIds.ts` — new `<EnumKey>` enum entry
- `.registryrc` — updated to registry commit `<commit-hash>`
- Agent config JSONs updated by `update-agent-config`

**Multi-collateral routes also include:**

- `typescript/infra/config/environments/mainnet3/governance/ica/warpFees.ts` — uncommented `<synthetic-chain>` entry
- `typescript/infra/config/environments/mainnet3/warp/configGetters/get<Name>WarpConfig.ts` — new configGetter
- `typescript/infra/config/warp.ts` — new import + map entries
- `typescript/infra/config/environments/mainnet3/rebalancer/<TOKEN>/<label>-config.yaml` — rebalancer config

🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"

Fill in real values:

  • <linear-issue-url>: full Linear ticket URL(s). If multiple routes, list each on its own row in the table, e.g.:
    | **Linear** | [AW-548](...) · [AW-551](...) |
    
  • Grafana URL: URL-encode the warp route ID (replace / with %2F, e.g. RISE%2Fbsc-ethereum). If multiple routes, list each on its own row.
  • <commit-hash>: the registry commit hash written to .registryrc in Step 3
  • Omit the multi-collateral section if all routes are simple routes
  • When batching multiple routes, repeat the warp route ID + Grafana rows for each route and list all changed files

Show the user the PR URL when done.


Notes

  • The repo-root pnpm agent-configs script reads .registryrc to determine which registry version to use, so updating .registryrc first is required. Always run from the repo root — the env-specific update-agent-config:mainnet3 lets testnet4 configs drift.
  • Do not skip steps — each depends on the previous
  • If any step fails, surface the error clearly and wait for user input

Signals

GitHub stars
75
Forks
601
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
warp-deploy-register-route
Source
github.com/hyperlane-xyz/hyperlane-monorepo