feat(dapp): custodial-only readiness + dApp release-please - #55
Merged
Merged
Conversation
… add dApp to release-please v1.0 ships custodial-only. Non-custodial code stays in the bundle behind a build-time flag so a flag-flipped build re-enables the full flow without code changes. Gating (UI-only — dashboard/transfer/balances already branch on profile.keyMode, so they need no changes): - New helper packages/dapp/src/lib/features.ts exports NON_CUSTODIAL_ENABLED = (import.meta.env.VITE_ENABLE_NON_CUSTODIAL === "true"). - App.tsx routes new users straight to custodial-pending instead of the registration-choice screen when the flag is off. The choice page and the two non-custodial registration pages still exist but their renderers are guarded by the flag so they're unreachable. - CustodialRegistrationPage.onBack is now optional; when omitted (flag off) the "← Back to registration" link and the inline "Cancel" button are hidden, since there's nowhere to go back to. - Bundle: 273 KB with flag off vs 283 KB with flag on — Vite tree-shakes the dead non-custodial branches. release-please: - Add packages/dapp to release-please-config.json with component=dapp. - Add packages/dapp: 0.1.0 to .release-please-manifest.json. - No publish step: only the snap is on npm; the dApp gets a tag + GitHub release + CHANGELOG entry on each user-facing dApp commit. Regular CI on the release PR validates the dApp builds.
There was a problem hiding this comment.
Code Review
This pull request introduces a build-time feature flag, NON_CUSTODIAL_ENABLED, to control the availability of the non-custodial registration flow, defaulting to a custodial-only experience for v1.0. Changes include conditional navigation logic in App.tsx, UI adjustments in CustodialRegistrationPage.tsx to hide back-links when the flag is disabled, and environment configuration updates. Feedback suggests refactoring the custodial flow entry logic into a reusable useCallback to eliminate code duplication and improve maintainability.
useSnap()'s mount effect called wallet_getSnaps unconditionally to detect a previously-installed snap. Standard MetaMask doesn't support that method and rejects with RPC 4100. The error was caught (returns null), so behavior was correct, but MetaMask logs the error before returning the rejection, and the failed RPC also showed up as 'StreamMiddleware - Unknown response id' noise. useRegistration() mounts useSnap() unconditionally, so even the custodial flow triggered the probe. Now the effect is gated on NON_CUSTODIAL_ENABLED — custodial-only builds never call any snap RPC, console stays clean, and standard MetaMask is fully supported.
…sn't reject stale chains ensureChainAdded() unconditionally called wallet_addEthereumChain when MM wasn't already on the target chainId. If MM had previously stored that chainId with a different nativeCurrency.symbol (e.g. an older dApp build that used a different name), MM returns -32602: 'nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId'. EIP-3326 covers this: switch first, fall back to add only on 4902 (chain not added). Switch tolerates symbol/name drift because it doesn't try to mutate the existing entry. Add still runs cleanly for a genuinely-unknown chain.
handleMetaMaskSign called addEthChain directly, bypassing the switch-first pattern in ensureChainAdded. If MM had the chain stored with even minor metadata drift (e.g. a previous Canton Devnet entry using a different nativeCurrency.symbol), every transfer attempt would hit -32602 'nativeCurrency.symbol does not match'. ensureChainAdded already does the right thing: switch first, fall back to add only on 4902. Drop the inline addEthChain + ethChainId calls and use the shared helper.
Bridge: drop the Bridge sidebar entry (was disabled), the BridgeIcon component, the 'Bridge assets' quick-action button on the profile page, and the Transfers/Bridge sub-tab toggle on the activity page along with its associated CSS. Activity now just shows transfers. Tab persistence: dashboardTab now syncs with window.location.hash, so refreshing on /#balances stays on Balances instead of snapping back to Profile. Hash updates use history.replaceState so back/forward across tabs works without polluting history with intermediate entries. The hash is only written while on the dashboard — landing/registration don't touch it.
… profile - Gemini review: handleCustodial is now a useCallback, and goRegister calls it instead of duplicating the setMode/setPage pair. - Self-review: the Profile page's 'CANTON SNAP — Not installed' block is now hidden for custodial users entirely. The block was always meaningless for them and looked like a warning in the v1.0 custodial- only build where useSnap's probe is also skipped.
Member
Author
|
Resolved the duplication in commit a842684 — |
salindne
self-requested a review
May 19, 2026 21:01
salindne
approved these changes
May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Prepares the dApp for a v1.0 custodial-only ship while preserving the non-custodial flow behind a flag, drops the disabled Bridge tab, hardens chain-add handling, persists the active dashboard tab across refresh, and wires the dApp into release-please.
Changes
VITE_ENABLE_NON_CUSTODIAL(default off). New users skip the choice screen and go straight to custodial registration. Snap RPC probes are skipped on standard MetaMask. Non-custodial code stays in the tree so a flag-flipped build re-enables the full flow without source changes.CustodialRegistrationPagehides its "← Back to registration" / "Cancel" controls when there's nowhere to go back to.DashboardProfilePagehides the "CANTON SNAP" status block for custodial users.BridgeIcon, "Bridge assets" quick action on Profile, Transfers/Bridge sub-tabs + orphan CSS on Activity all gone.ensureChainAdded(network.ts) and now routed through byTransferPage. Avoids the-32602 nativeCurrency.symbol does not match …failure when MetaMask has the chain stored with stale metadata.window.location.hashmirroring inApp.tsx./#balancessurvives a reload; browser back/forward navigates tabs.packages/dappregistered withcomponent=dapp. No publish job — the dApp isprivate: true, so release-please just bumpspackage.json, writespackages/dapp/CHANGELOG.md, tagsdapp-vX.Y.Z, and creates a GitHub release on merge. The existing snap publish job is unchanged.Bundle impact
Vite tree-shakes dead non-custodial branches when the flag is off.
Test plan
npm run lintclean.npm -w packages/dapp run buildclean (custodial-only build).VITE_ENABLE_NON_CUSTODIAL=true npm -w packages/dapp run buildclean (full build).window.ethereumcollision.Future cleanup (next milestones)
NON_CUSTODIAL_ENABLEDbranch + non-custodial pages.