Skip to content

feat(chains): registry-driven wagmi + wrong-chain guard#12

Merged
fielding merged 2 commits into
mainfrom
feat/wagmi-multichain
Apr 26, 2026
Merged

feat(chains): registry-driven wagmi + wrong-chain guard#12
fielding merged 2 commits into
mainfrom
feat/wagmi-multichain

Conversation

@fielding

Copy link
Copy Markdown
Owner

Summary

Stacked on #11 (chain: feat/page-refactor → feat/chain-registry → main). Closes `RG-b53952`.

Two pieces:

  1. wagmi.ts derives its chains list from the registry. Instead of hardcoded `[isTestnet ? baseSepolia : base]`, the wagmi config walks `CHAINS` and filters by the deployment's `isTestnet` flag. Adding a chain to `chains.ts` (with a matching wagmi mapping) auto-expands the wallet picker.

  2. `WrongChainPanel` component. Wraps the form on `/create` and the dashboard on `/vaults`. When `useChainId()` returns a chainId not in our registry, it swaps the children for a "switch your wallet" prompt that calls `useSwitchChain` from wagmi. Plus defensive fallbacks (`isSupportedChain(chainId) ? chainId : DEFAULT_CHAIN_ID`) on every `getChainConfig` call so unsupported chains don't crash render before the panel can show.

Why this PR doesn't visibly add 6 new chains

The handoff plan calls for Ethereum + Arbitrum + Optimism + Polygon + Avalanche + BNB. I deliberately kept the registry at Base + Base Sepolia in this PR for two reasons:

  1. Address verification is ops work, not code work. Sablier Lockup v2.0 addresses on the other 6 chains need to be looked up from Sablier docs and verified. Putting placeholder zero addresses in the registry would either (a) silently break tx attempts on those chains or (b) require a parallel `live: false` flag that adds churn. Either way, the right place is `RG-644a80` (per-chain ops), which is the task explicitly scoped for that verification.
  2. Wallet picker UX integrity. If wagmi shows a chain in its picker, users expect to be able to use it. Showing 6 chains where 5 are dead and only Base works erodes trust on a product whose entire pitch is "this protocol doesn't lie to you." Better to ship the infrastructure and turn chains on as ops verifies them — which this PR makes a one-line change.

When `RG-644a80` lands real addresses, those entries automatically appear in the wallet picker via the registry → wagmi derivation. No further code change to wagmi.ts.

What changes for users today

  • A user whose wallet is on Polygon visiting `ripguard.xyz/create` no longer crashes (regression introduced by feat(pages): per-chain page lookups + decimal-aware approve/lock flow #11). They see a "switch your wallet to Base" prompt with a one-click switch button.
  • Same on `/vaults`.
  • The landing falls back to Base for the "view contract" link (would have crashed without the fallback).
  • The wallet picker still shows just Base on mainnet, Base Sepolia on testnet. Identical to today.

Test plan

  • `pnpm --filter app test` — 68 tests pass
  • `pnpm --filter app exec tsc --noEmit` — clean
  • `NODE_ENV=production pnpm --filter app build` — clean
  • Smoke test on Vercel preview: switch MetaMask to mainnet Ethereum, visit `/create` — should see "switch to Base" panel, not a crash. Switch back to Base, panel disappears, form returns.
  • Same test on `/vaults`.
  • On the testnet deploy, MetaMask on Base Sepolia: form shows. MetaMask on Base mainnet: panel asks to switch to Base Sepolia.

Open question for you

Want me to also add the 6 chain entries with `live: false` flags as a follow-up PR, so the structure is visible in the registry before `RG-644a80` populates real addresses? Or hold and do it as part of `RG-644a80` when the addresses are also being added? Either is fine — the wagmi config is ready to absorb them.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Apr 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ripguard Ready Ready Preview, Comment Apr 26, 2026 8:20am
ripguard-testnet Ready Ready Preview, Comment Apr 26, 2026 8:20am

@fielding

Copy link
Copy Markdown
Owner Author

Reviewer orientation — multi-EVM stack [3/6]

This PR is part of a 6-PR stacked multi-EVM rollout. Review #8 and #11 first — this layer's wrong-chain guard fixes a regression #11 introduces.

PR Branch What it does
1 #8 feat/chain-registry registry foundation
2 #11 feat/page-refactor switch pages to useChainId
→ 3 #12 feat/wagmi-multichain wagmi + wrong-chain guard (you are here)
4 #13 feat/expand-chains add 6 new chains + BNB disclosure
5 #14 feat/landing-chain-chips landing chain chip row
6 #15 feat/balances-script `pnpm balances` CLI

Move to #13 when done.

After this PR, the foundation is complete but no new chains are visible to users yet — wallet picker still shows just Base on mainnet. #13 flips on the 6 new chains with verified Sablier + USDC addresses.

@fielding fielding left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on this layer.

WrongChainPanel and the defensive getChainConfig fallbacks check isSupportedChain(chainId), which means "exists anywhere in the registry." It does not mean "supported by this deployment."

That matters because the registry contains both mainnet chains and Base Sepolia:

  • On the testnet deployment, a wallet on Base mainnet, Arbitrum, BNB, etc. is treated as supported.
  • On the mainnet deployment, a wallet on Base Sepolia is treated as supported.
  • The wrong-chain panel will not show.
  • /create and /vaults will resolve config for the opposite deployment instead of falling back to the deployment default.

This contradicts the PR test plan item that says Base mainnet on the testnet deploy should ask the user to switch to Base Sepolia.

Please make support deployment-aware, for example:

export function isSupportedDeploymentChain(
  chainId: number | undefined,
  isTestnet: boolean,
): chainId is number {
  return (
    chainId !== undefined &&
    isSupportedChain(chainId) &&
    getChainConfig(chainId).isTestnet === isTestnet
  );
}

Then use that in:

  • WrongChainPanel
  • /create fallback lookup
  • /vaults fallback lookup
  • landing fallback lookup

So the fallback becomes:

getChainConfig(
  isSupportedDeploymentChain(chainId, IS_TESTNET)
    ? chainId
    : DEFAULT_CHAIN_ID
)

The panel already filters the switch buttons by IS_TESTNET, so this should be a small change.

fielding added a commit that referenced this pull request Apr 25, 2026
Addresses review feedback on #12.

isSupportedChain returns true for any chain in the registry — which
includes both mainnets and Base Sepolia. That made the wrong-chain
guard wrong twice over: a wallet on mainnet visiting the testnet
deployment was treated as supported (and got resolved to a real
mainnet chain config), and a wallet on Base Sepolia visiting the
mainnet deployment got the testnet config back.

New helper isSupportedDeploymentChain(chainId, isTestnet) checks
both registry membership AND that the chain's testnet flag matches
the deployment's. Used everywhere we previously called isSupportedChain
to gate fallback behavior:

- WrongChainPanel: now shows the panel for cross-deployment wallets
- /create defensive lookup: falls back to deployment default
- /vaults defensive lookup: same
- landing defensive lookup: same

isSupportedChain stays exported for any caller that genuinely wants
"is this in the registry at all" (e.g., share-card path verification).

Test covers all four matrix cases: mainnet chain on mainnet ✓,
mainnet on testnet ✗, testnet on mainnet ✗, testnet on testnet ✓.

Refs: RG-b53952 (review feedback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fielding fielding force-pushed the feat/wagmi-multichain branch from c2e6c29 to 1da66b7 Compare April 25, 2026 21:53
@fielding

Copy link
Copy Markdown
Owner Author

Pushed fix addressing your changes-requested review.

Added `isSupportedDeploymentChain(chainId, isTestnet)` to chains.ts — checks both registry membership AND that the chain's `isTestnet` flag matches the deployment's. Used everywhere `isSupportedChain` was previously gating fallback behavior:

  • `WrongChainPanel` — now shows the panel for cross-deployment wallets (mainnet wallet on testnet deploy, etc.)
  • `/create` defensive lookup
  • `/vaults` defensive lookup
  • landing defensive lookup

`isSupportedChain` stays exported for callers that genuinely want "is this anywhere in the registry" — e.g., share-card path verification — but no chain-gating logic uses it anymore.

Test covers the full matrix: mainnet on mainnet ✓, mainnet on testnet ✗, testnet on mainnet ✗, testnet on testnet ✓, unregistered ✗ either way.

Tests + typecheck + production build pass. Ready for re-review.

@fielding fielding left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed after the deployment-aware guard fix. The blocker from my prior review is addressed.

isSupportedDeploymentChain(chainId, IS_TESTNET) is now used for the wrong-chain panel and all defensive lookups, and the test matrix covers mainnet-vs-testnet mismatches. Mainnet wallets should no longer slip through on the testnet deploy, and Base Sepolia should no longer slip through on the mainnet deploy.

I do not see remaining blockers in this layer.

@fielding fielding force-pushed the feat/page-refactor branch from 1ee87e0 to bd644d3 Compare April 26, 2026 08:07
@fielding fielding changed the base branch from feat/page-refactor to main April 26, 2026 08:10
fielding and others added 2 commits April 26, 2026 03:10
wagmi.ts now derives its chains array from the registry, filtered by
the deployment's testnet flag. Adding a chain to chains.ts (with a
matching entry in the chainIdToWagmiChain map) auto-expands the wallet
picker — no more manual sync between two sources of truth.

Today the wallet picker still shows only Base on the mainnet site
(Base Sepolia on testnet) because those are the only registry entries.
RG-644a80 will populate Ethereum, Arbitrum, Optimism, Polygon,
Avalanche, and BNB Chain entries with verified Sablier v2.0 + USDC
addresses; once those land in chains.ts, this PR's wagmi derivation
will pick them up automatically.

WrongChainPanel: a new client component that swaps the page content
for a "switch your wallet" prompt when useChainId() returns a
chainId not in our registry. Used to guard /create (block tx flow)
and /vaults (block stream queries). The landing falls back to the
default chain's contract link so the page still renders normally.

Defensive fallback in /create, /vaults, and /. Before this PR, a user
manually switching their wallet to an unsupported chain (e.g. mainnet
Ethereum on the Base deployment) would crash the page on
getChainConfig(chainId) throwing. Now those pages fall back to
DEFAULT_CHAIN_ID for display values; WrongChainPanel handles the UX.

Refs: RG-b53952

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses review feedback on #12.

isSupportedChain returns true for any chain in the registry — which
includes both mainnets and Base Sepolia. That made the wrong-chain
guard wrong twice over: a wallet on mainnet visiting the testnet
deployment was treated as supported (and got resolved to a real
mainnet chain config), and a wallet on Base Sepolia visiting the
mainnet deployment got the testnet config back.

New helper isSupportedDeploymentChain(chainId, isTestnet) checks
both registry membership AND that the chain's testnet flag matches
the deployment's. Used everywhere we previously called isSupportedChain
to gate fallback behavior:

- WrongChainPanel: now shows the panel for cross-deployment wallets
- /create defensive lookup: falls back to deployment default
- /vaults defensive lookup: same
- landing defensive lookup: same

isSupportedChain stays exported for any caller that genuinely wants
"is this in the registry at all" (e.g., share-card path verification).

Test covers all four matrix cases: mainnet chain on mainnet ✓,
mainnet on testnet ✗, testnet on mainnet ✗, testnet on testnet ✓.

Refs: RG-b53952 (review feedback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fielding fielding force-pushed the feat/wagmi-multichain branch from 1da66b7 to f9db0a0 Compare April 26, 2026 08:10
@fielding fielding merged commit 79c2fc7 into main Apr 26, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant