Skip to content

feat: support explicit chain configuration in UI kit (Sepolia, Gnosis, local)#5

Open
franrolotti wants to merge 4 commits intomainfrom
sepolia-chain-config
Open

feat: support explicit chain configuration in UI kit (Sepolia, Gnosis, local)#5
franrolotti wants to merge 4 commits intomainfrom
sepolia-chain-config

Conversation

@franrolotti
Copy link

Summary

This PR removes isProd-driven chain behavior from critical auth/read/status flows and introduces explicit chain configuration via BreadUIKitProvider, so Sepolia (11155111) is supported as a first-class network without breaking Gnosis (100) or local (31337).

What changed

1) Provider-level explicit chain config

  • Added chainId and supportedChainIds support in BreadUIKitProvider.
  • Kept backward-compatible fallback via isProd (true -> 100, false -> 31337).
  • Preserved legacy token override behavior only when using legacy isProd-derived chain path.

2) Login / switch-chain flow

  • Privy Change network now switches to configured chainId from context.
  • Removed isProd dependency from login button flow.

3) Connected user status logic

  • Both connected-user providers (general + privy) now determine support using supportedChainIds.
  • Sepolia is treated as supported when configured.

4) Read hooks

  • useBreadBalance now reads with context chainId (no isProd chain derivation).

5) Account widget chain hardcoding removed

  • Replaced hardcoded Gnosis explorer/name with dynamic chain data:
    • Explorer URL from chain.blockExplorers?.default.url
    • Network label from chain.name

6) Docs + helper updates

  • Added README section for Web3 chain configuration and migration notes.
  • Updated getActiveChainId helper to support explicit numeric chain IDs while retaining legacy boolean fallback.

Expected behavior after this PR

  • Sepolia (11155111)
    • No forced switch to 100
    • Login + chain switching target Sepolia when configured
    • Connected state resolves correctly when Sepolia is in supportedChainIds
  • Gnosis (100)
    • Existing behavior preserved
  • Local (31337)
    • Existing behavior preserved

Backward compatibility

  • isProd fallback remains supported for existing consumers.
  • New recommended API is explicit: chainId (+ optional supportedChainIds).

@netlify
Copy link

netlify bot commented Mar 11, 2026

Deploy Preview for breadcoopstorybook ready!

Name Link
🔨 Latest commit 8939b96
🔍 Latest deploy log https://app.netlify.com/projects/breadcoopstorybook/deploys/69b15489b9a74600085959a4
😎 Deploy Preview https://deploy-preview-5--breadcoopstorybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@tbsoc
Copy link
Member

tbsoc commented Mar 11, 2026

🤖 AI Code Review

Code Review: Explicit Chain Configuration Support

1. Summary

This PR successfully migrates the Bread UI kit from an isProd boolean flag to explicit chain configuration. It introduces chainId and supportedChainIds props on BreadUIKitProvider, removes hardcoded Gnosis assumptions from the account widget, and updates both Privy and general auth providers to respect the new configuration. The legacy isProd fallback remains for backward compatibility.


2. Code Quality

Architecture

Duplicated logic: Both privy-provider.tsx and provider-general.tsx contain identical resolveChain functions. Extract this to a shared utility:

// src/utils/chains.ts
export function resolveChain(chainId: number): Chain {
  const chains = [gnosis, anvil, sepolia];
  return chains.find(c => c.id === chainId) ?? sepolia;
}

Missing context defaults: The provider destructures supportedChainIds without a fallback. If consumers pass only chainId, supportedChainIds becomes undefined and includes() will throw:

// Add sensible defaults in BreadUIKitProvider
const resolvedSupportedChainIds = supportedChainIds ?? [chainId ?? (isProd ? 100 : 31337)];

Surprising fallback behavior: resolveChain silently defaults to Sepolia for unknown chain IDs. This masks configuration errors. Consider returning null or throwing instead, letting the UI render an "unsupported chain" state explicitly.

Readability

The LoginButtonPrivyProps interface marks isProd as deprecated but doesn't use JSDoc deprecation format. Use:

/** @deprecated Chain behavior is now controlled via BreadUIKitProvider config. */
isProd?: boolean;

The resolveChain function name is vague—getChainById or lookupChainConfig is clearer.


3. Security

Block explorer URL construction: The account widget constructs URLs with:

const accountUrl = explorerUrl ? `${explorerUrl}/address/${userAddress || ""}` : undefined;

userAddress is already validated as Address by TypeScript, but explorerUrl comes from chain.blockExplorers?.default.url which is user-controlled config. Add validation:

const explorerUrl = chain.blockExplorers?.default.url;
if (explorerUrl && !URL.canParse(explorerUrl)) {
  console.error("Invalid explorer URL in chain config");
  return undefined;
}

Chain switching error handling: The switch-chain flow logs errors to console but doesn't surface them to users. Failed network switches should propagate to the UI so users aren't left wondering why nothing happened.


4. Suggestions

Priority Location Change
High context/lib.tsx Add supportedChainIds default fallback to prevent runtime crashes
High utils/chains.ts Create shared resolveChain utility; remove duplicates from providers
Medium navbar/account-widget.tsx Validate explorerUrl before constructing links
Medium auth/login-button-privy.tsx Surface switchChain errors to UI, not just console
Low README.md Add explicit note that chainId must be in supportedChainIds or it won't be treated as valid
Low All providers Add debug logging for which chain is resolved (helps with "why is Sepolia showing?" issues)

Type safety nit: In privy-provider.tsx, embeddedWallet.chainId is parsed with parseInt but never validated as a number. Consider:

const currentChainId = walletChainId 
  ? parseInt(walletChainId.split(":")[1], 10) 
  : undefined;
if (currentChainId && isNaN(currentChainId)) {
  // handle malformed chain ID
}

Overall Assessment

Solid migration that achieves its goals. The main blockers are the missing supportedChainIds default (will crash existing consumers who only pass isProd) and the duplicated resolveChain logic. Fix those and this is ready to ship.

@franrolotti
Copy link
Author

PR Review: feat: support explicit chain configuration in UI kit (Sepolia, Gnosis, local)

Overall

This is a strong refactor that cleanly removes isProd coupling from runtime chain behavior and introduces explicit, flexible chain configuration via BreadUIKitProvider. The implementation aligns with the PR intent and preserves backward compatibility for existing consumers.

What Looks Good

  • Explicit chainId / supportedChainIds are now the primary source of truth.
  • Legacy fallback (isProd -> 100/31337) is preserved for compatibility.
  • Privy switch-network flow now correctly targets configured chainId.
  • Connected-user status logic is generalized and no longer hardcoded to Gnosis/local only.
  • useBreadBalance now reads from context chainId, which fixes implicit network assumptions.
  • Account widget no longer hardcodes Gnosis explorer/name and now uses chain metadata.
  • README migration guidance is clear and practical.

Behavioral Validation (Against PR Goals)

  • Sepolia (11155111): supported as first-class when configured; no forced Gnosis switching.
  • Gnosis (100): legacy/default behavior preserved.
  • Local (31337): legacy/default behavior preserved.
  • Supported-chain checks now correctly use supportedChainIds in both general and Privy providers.

Minor Risks / Follow-ups (Non-blocking)

  1. isProd + chainId can become semantically inconsistent if both are passed with conflicting values (behavior follows chainId, while some consumers might still read isProd).
  2. Privy chainId parsing still assumes CAIP-2 format (eip155:<id>); unexpected formats will resolve to unsupported.

Suggested Optional Improvements

  • Add a dev warning when isProd conflicts with explicit chainId.
  • Add unit tests for:
    • chainId inclusion into supportedChainIds
    • Privy chain parsing / unsupported fallback
    • Legacy token override behavior only on legacy isProd path

Verdict

Approve — implementation is correct for scope, backward compatible, and meaningfully improves multi-chain correctness (especially Sepolia support).

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.

2 participants