Skip to content

feat(chains): expand registry to 7 EVM mainnet chains + BNB disclosure#13

Merged
fielding merged 2 commits into
mainfrom
feat/expand-chains
Apr 26, 2026
Merged

feat(chains): expand registry to 7 EVM mainnet chains + BNB disclosure#13
fielding merged 2 commits into
mainfrom
feat/expand-chains

Conversation

@fielding

Copy link
Copy Markdown
Owner

Summary

Stacked on #12. Expands the registry from Base + Base Sepolia to all 7 target EVM mainnet chains plus Base Sepolia. Closes the data-wiring portion of `RG-644a80`; smoke testing remains.

Verification trail

Sablier Lockup v2.0 — sourced from `sablier-labs/sdk`'s deployment broadcasts (their canonical Foundry output). I read each chain's `deployments/lockup/v2.0/broadcasts/.json` directly via the GitHub API. The two values that already existed in our codebase (Base mainnet `0xb5D78DD3...` and Base Sepolia `0xa4777CA5...`) match the canonical source byte-for-byte — strong evidence the unknown 6 are also right. Spot-checked the BNB broadcast JSON and confirmed `contractName === "SablierLockup"` and `chain === 56`. All deployments use CREATE2 with deterministic salts (per the v2.0 README), which is why Base mainnet's address is the same one already serving production.

Native USDC — sourced from Circle's official contract addresses page. All 6 mainnet chains except BNB have Circle-issued native USDC at 6 decimals.

BNB Chain USDC — Circle does NOT issue native USDC on BNB. The token at `0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d` is Binance-Peg USD Coin, custodied by Binance, with 18 decimals. Verified on Bscscan (the page literally warns "this token's displayed name does not match its contract's Name function"). The new `usdcNote` field on the chain entry disclosures this; `/create` and `/vaults` render the note when active.

Sablier deployment blocks — pulled from each chain's broadcast JSON (`min(receipts[].blockNumber)`). These are the tightest safe `streamStartBlock` values for the on-chain `getLogs` fallback. Base mainnet stays at the existing `22_000_000` (already-shipped value, no behavior change there).

Final addresses

Chain Sablier Lockup v2.0 Native USDC Decimals
Ethereum (1) `0x7C01AA37...d5b21056` `0xA0b86991...3606eB48` 6
Base (8453) `0xb5D78DD3...28e0Fe3B` `0x833589fC...bdA02913` 6
Arbitrum One (42161) `0x467D5Bf8...8934b725` `0xaf88d065...268e5831` 6
Optimism (10) `0x822e9c48...c2b700c1` `0x0b2C639c...097Ff85` 6
Polygon (137) `0xE0BFe071...512C1Ff4` `0x3c499c54...d5c3359` 6
Avalanche (43114) `0x3C81BBBe...0dd27E82` `0xB97EF9Ef...c48a6E` 6
BNB Chain (56) `0x6E0baD2c...AfBEd395` `0x8AC76a51...32Cd580d` (Binance-Peg) 18
Base Sepolia (84532) `0xa4777CA5...d7416f8d` `0x54C0f145...F1EC0009` (TestUSDC) 6

Treasury — same EOA across all 7 mainnet chains

`0x847F640bE052b0700C31F72Dce622F4C6286934E` is an EOA with an EIP-7702 delegation set on Base mainnet only. Underlying key gives the same address on every EVM chain; the 7702 delegation is per-chain and doesn't change token-receipt behavior. Confirmed via `viem.getCode()` against the Base mainnet RPC. Test asserts treasury parity across mainnet entries.

What changes for users

  • The wallet picker now shows all 7 mainnet chains on the production deployment (testnet deployment still only Base Sepolia, since registry filter on `isTestnet`).
  • A user on BNB Chain sees: "On BNB Chain, USDC is Binance-Peg (custodied by Binance, 18 decimals)." — quiet line under the balance display on `/create`, top of the dashboard on `/vaults`.
  • A user on any other supported chain sees the form exactly as today, with chain-specific addresses + decimals applied transparently.

Test plan

  • `pnpm --filter app test` — 72 tests pass (was 68; +4 new chain registry tests)
  • `pnpm --filter app exec tsc --noEmit` — clean
  • `NODE_ENV=production pnpm --filter app build` — clean
  • Vercel preview: connect to each of 7 chains via RainbowKit's switcher, confirm the page renders and the Sablier address in the form footer matches the table above
  • Smoke test before merging to main: do one tiny lock + claim cycle on Arbitrum (cheapest gas) to confirm broker fee routes to the treasury and stream creation works end-to-end. BNB second to validate the 18-decimal handling.

Note on the next PR

Now that the registry is full, PR 4 (`RG-213ce7`, landing chain chip row) has real data to render. I'll stack that next.

🤖 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:23am
ripguard-testnet Ready Ready Preview, Comment Apr 26, 2026 8:23am

@fielding

Copy link
Copy Markdown
Owner Author

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

This PR is part of a 6-PR stacked multi-EVM rollout. Review #8, #11, and #12 first — this PR fills in chain data on top of that foundation.

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 registry-driven wagmi + wrong-chain guard
→ 4 #13 feat/expand-chains 6 new chains + BNB disclosure (you are here)
5 #14 feat/landing-chain-chips landing chain chip row
6 #15 feat/balances-script `pnpm balances` CLI

Move to #14 when done.

This is the user-facing PR. Sablier addresses pulled directly from `sablier-labs/sdk` deployment broadcasts (canonical Foundry output, verified against the 2 known-good Base values which match exactly). USDC addresses from Circle's official docs. BNB sharp edge: USDC on BNB is Binance-Peg, 18 decimals, custodied by Binance — disclosed via `usdcNote` in the registry, surfaced on `/create` and `/vaults`. Test enforces BNB stays at 18 decimals.

Smoke test before merging this: one Arbitrum lock+claim cycle (cheapest gas), one BNB lock+claim cycle (validates 18-decimal handling). Full checklist at `.handoff/SMOKE_TEST_MULTI_EVM.md`.

@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 before this layer exposes the new chains.

The chain data itself looks good. I checked the Sablier Lockup v2.0 addresses against Sablier's docs, and the entries in this PR match the published v2.0 deployments. The BNB 18-decimal disclosure is also the right call.

The issue is that enabling non-Base chains makes the existing hardcoded BaseScan copy wrong. The URLs are chain-derived now, but labels and explanatory text still say BaseScan in several places:

  • /create tx toast/link labels
  • /vaults claim toast label
  • landing verification copy and FAQ copy
  • footer explorer nav label

On Arbitrum, Polygon, BNB, etc. those links go to the right explorer but the UI says BaseScan. Please switch these to generic copy like "View transaction", "block explorer", or a chain-derived explorer label before exposing the chains.

Also, this PR inherits the lower-stack blockers I left on #11 and #12:

  • active tx flows need to handle chain changes safely
  • wrong-chain support needs to be deployment-aware, not just registry-aware

Non-blocking: Object.values(CHAINS) gives numeric-key order, so the effective order is Ethereum, Optimism, BNB, Polygon, Base, Arbitrum, Avalanche. If you want Base first, use an explicit ordered chain list and reuse it for wagmi/chips/scripts.

Validation I ran on the top of the stack:

pnpm --filter app test
pnpm --filter app exec tsc --noEmit
NODE_ENV=production pnpm --filter app build

All passed. I could not run the Vercel preview smoke checklist because the preview URL redirected me to Vercel login from this environment.

@fielding fielding force-pushed the feat/wagmi-multichain branch from c2e6c29 to 1da66b7 Compare April 25, 2026 21:53
fielding added a commit that referenced this pull request Apr 25, 2026
Addresses review feedback on #13: enabling non-Base chains made every
hardcoded "BaseScan" reference wrong. The URLs were already chain-
derived, but the labels weren't, so a user on Arbitrum saw "View on
BaseScan" linking to Arbiscan.

Adds explorerName to ChainConfig (Etherscan, BaseScan, Arbiscan,
Optimistic Etherscan, PolygonScan, Snowtrace, BscScan, Base Sepolia
BaseScan) and threads it through:

- /create toast: "Lock created!" → "View on {explorerName}"
- /create approve confirming link: "View on {explorerName}"
- /create lock confirming link: "View on {explorerName}"
- /create SuccessView: "View transaction on {explorerName}"
  (now takes explorerName as a prop alongside explorerUrl)
- /vaults claim toast: "View on {explorerName}"
- landing footer link: "{explorerName}" instead of literal "BaseScan"

Static landing copy that doesn't sit next to a connected chain
(TRUST_POINTS, FAQ, footer disclaimer) is generalized to "the chain's
block explorer" since it's marketing copy, not a per-chain label.
The hardcoded "on Base" in the footer disclaimer also goes away —
RipGuard now runs on 7 chains.

Lock success effect deps now include explorerName so the toast picks
up the active chain's value when the user changes networks.

Refs: RG-644a80 (review feedback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fielding fielding force-pushed the feat/expand-chains branch from 03252aa to 458e6dd Compare April 25, 2026 21:57
@fielding

Copy link
Copy Markdown
Owner Author

Pushed fix addressing your changes-requested review.

Replaced every hardcoded "BaseScan" with chain-aware copy. Added `explorerName` to `ChainConfig` (Etherscan, BaseScan, Arbiscan, Optimistic Etherscan, PolygonScan, Snowtrace, BscScan, Base Sepolia BaseScan) and threaded it through:

  • `/create` lock-success toast: "View on {explorerName}"
  • `/create` approve-confirming link: "View on {explorerName}"
  • `/create` lock-confirming link: "View on {explorerName}"
  • `/create` SuccessView "View transaction on {explorerName}" (now takes explorerName as a prop)
  • `/vaults` claim-success toast: "View on {explorerName}"
  • landing footer link: `{explorerName}` instead of hardcoded "BaseScan"

Static landing copy (TRUST_POINTS, FAQ, footer disclaimer) is generalized to "the chain's block explorer" since it's marketing copy not tied to a connected chain. The hardcoded "on Base" in the footer disclaimer also goes away.

Lock-success effect deps include `explorerName` so the toast picks up the active chain's name when the user changes networks.

The two lower-stack blockers you flagged are also fixed — see updates on #11 (chain-aware deps + chain-change guard + namespaced localStorage key) and #12 (deployment-aware support check). Stack rebased clean on top of those.

Non-blocking ordering note: the chip row's Object.values order is also affecting #14's PR description. Holding on the explicit-ordered-chains list change for now since it's non-blocking and would be one more rebase round across the stack — happy to add it as a follow-up if you'd rather see it now.

Tests + typecheck + production build pass on top of stack. 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 explorer-name copy fix. The blocker from my prior review is addressed.

The tx links now use explorerName, landing copy is generalized where it should be, and the footer explorer label is chain-aware. The lower-stack blockers from #11 and #12 are also fixed in the current stack.

I do not see remaining code blockers in this layer. The manual Arbitrum and BNB smoke tests are still the merge gate for this user-facing chain expansion.

@fielding fielding force-pushed the feat/wagmi-multichain branch from 1da66b7 to f9db0a0 Compare April 26, 2026 08:10
@fielding fielding changed the base branch from feat/wagmi-multichain to main April 26, 2026 08:11
fielding and others added 2 commits April 26, 2026 03:11
Expands the registry from Base + Base Sepolia to all 7 target EVM
mainnet chains plus Base Sepolia. Sablier Lockup v2.0 addresses
sourced directly from sablier-labs/sdk's deployment broadcasts;
verified against the two known-good values (Base mainnet + Base
Sepolia) which match exactly. Native USDC addresses sourced from
Circle's official contract addresses page.

Sharp edges captured:

1. BNB Chain "USDC" is Binance-Peg, NOT Circle-native. The token at
   0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d is custodied by
   Binance and uses 18 decimals (every other chain's USDC is 6).
   The chain entry carries a usdcNote field disclosing this; /create
   and /vaults render the note when chainId === 56 so users see the
   distinction before they lock. Test enforces that BNB stays at 18
   decimals and every other chain stays at 6.

2. Treasury is the same EOA on every mainnet chain. EVM addresses
   derive from public keys, so the same private key gives the same
   address everywhere. The Base treasury has an EIP-7702 delegation,
   but that's per-chain and doesn't change token-receipt behavior.
   Test asserts treasury parity across mainnet chains.

3. Sablier streamStartBlock is set to each chain's exact v2.0
   deployment block (pulled from Sablier's deployment broadcasts).
   Tightest safe value for the on-chain getLogs fallback when the
   indexer is unavailable.

wagmi.ts auto-picks up the new entries via the chainIdToWagmiChain
map — no further config change needed. Wallet picker now shows all
7 mainnet chains; testnet deployment still shows only Base Sepolia.

Refs: RG-644a80 (data wiring portion; smoke testing remains)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses review feedback on #13: enabling non-Base chains made every
hardcoded "BaseScan" reference wrong. The URLs were already chain-
derived, but the labels weren't, so a user on Arbitrum saw "View on
BaseScan" linking to Arbiscan.

Adds explorerName to ChainConfig (Etherscan, BaseScan, Arbiscan,
Optimistic Etherscan, PolygonScan, Snowtrace, BscScan, Base Sepolia
BaseScan) and threads it through:

- /create toast: "Lock created!" → "View on {explorerName}"
- /create approve confirming link: "View on {explorerName}"
- /create lock confirming link: "View on {explorerName}"
- /create SuccessView: "View transaction on {explorerName}"
  (now takes explorerName as a prop alongside explorerUrl)
- /vaults claim toast: "View on {explorerName}"
- landing footer link: "{explorerName}" instead of literal "BaseScan"

Static landing copy that doesn't sit next to a connected chain
(TRUST_POINTS, FAQ, footer disclaimer) is generalized to "the chain's
block explorer" since it's marketing copy, not a per-chain label.
The hardcoded "on Base" in the footer disclaimer also goes away —
RipGuard now runs on 7 chains.

Lock success effect deps now include explorerName so the toast picks
up the active chain's value when the user changes networks.

Refs: RG-644a80 (review feedback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fielding fielding force-pushed the feat/expand-chains branch from 458e6dd to d98faf9 Compare April 26, 2026 08:11
@fielding fielding merged commit 1ca11f6 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