Problem
src/lib/wallet.ts#connectWallet and signTransaction call directly into @stellar/freighter-api with no handling for the extension being absent, locked, on the wrong network, or the user rejecting the permission prompt mid-flow. isFreighterInstalled checks freighterIsConnected(), but nothing in WalletContext.tsx or the /connect flow re-verifies network match before a signing operation is attempted from IssueActions.tsx or MilestoneActions.tsx. Given STELLAR_NETWORK is an env-driven constant (TESTNET default) and Freighter itself has an independently user-selected network, there is a realistic scenario where a contributor has Freighter set to Stellar PUBLIC while the app is configured for TESTNET (or vice versa after an env misconfiguration), and signTransaction will happily sign a transaction with the wrong network passphrase, producing a transaction Soroban will reject — but only after the user has already approved it in the extension, burning their attention and creating a confusing "why did my claim fail" support case.
Why this is hard
- Freighter's API surface (
isConnected, isAllowed, setAllowed, getAddress, signTransaction) doesn't expose "what network is the extension currently on" in a stable way across Freighter versions — you'll need to research the current @stellar/freighter-api version pinned in package.json (^6.0.1) and determine what's actually available (e.g. getNetwork/getNetworkDetails) and handle it being undefined on older installed extension versions.
- You must design a pre-flight check that runs before every
signTransaction call site (currently there's only one wrapper, but callers in IssueActions.tsx/MilestoneActions.tsx need to be identified and each guarded) without introducing a race between the check and the actual sign call (user could switch networks in the extension between the two).
- Error surfaces must be humane: distinguish "extension not installed," "extension locked," "wrong network," "user rejected," and "unknown error" with different UI treatments — right now
connectWallet collapses everything into generic thrown Errors.
WalletContext's WALLET_KEY localStorage persistence needs to be reconciled: what happens on next page load if the persisted address no longer matches the currently unlocked Freighter account?
Scope
- Add a network-mismatch pre-flight check used by every signing call site.
- Expand
WalletConnection/error types to a discriminated union covering the failure modes above.
- Update
WalletContext.tsx to expose a networkMismatch boolean and surface it in the connect UI.
- Add graceful re-sync when the stored address diverges from the live extension address on mount.
Acceptance criteria
- Simulate (via mocking
@stellar/freighter-api) each failure mode and confirm distinct, correct UI messaging.
- No transaction signing is attempted when a network mismatch is detected; the user is blocked with an actionable message instead.
Problem
src/lib/wallet.ts#connectWalletandsignTransactioncall directly into@stellar/freighter-apiwith no handling for the extension being absent, locked, on the wrong network, or the user rejecting the permission prompt mid-flow.isFreighterInstalledchecksfreighterIsConnected(), but nothing inWalletContext.tsxor the/connectflow re-verifies network match before a signing operation is attempted fromIssueActions.tsxorMilestoneActions.tsx. GivenSTELLAR_NETWORKis an env-driven constant (TESTNETdefault) and Freighter itself has an independently user-selected network, there is a realistic scenario where a contributor has Freighter set to StellarPUBLICwhile the app is configured forTESTNET(or vice versa after an env misconfiguration), andsignTransactionwill happily sign a transaction with the wrong network passphrase, producing a transaction Soroban will reject — but only after the user has already approved it in the extension, burning their attention and creating a confusing "why did my claim fail" support case.Why this is hard
isConnected,isAllowed,setAllowed,getAddress,signTransaction) doesn't expose "what network is the extension currently on" in a stable way across Freighter versions — you'll need to research the current@stellar/freighter-apiversion pinned inpackage.json(^6.0.1) and determine what's actually available (e.g.getNetwork/getNetworkDetails) and handle it being undefined on older installed extension versions.signTransactioncall site (currently there's only one wrapper, but callers inIssueActions.tsx/MilestoneActions.tsxneed to be identified and each guarded) without introducing a race between the check and the actual sign call (user could switch networks in the extension between the two).connectWalletcollapses everything into generic thrownErrors.WalletContext'sWALLET_KEYlocalStorage persistence needs to be reconciled: what happens on next page load if the persisted address no longer matches the currently unlocked Freighter account?Scope
WalletConnection/error types to a discriminated union covering the failure modes above.WalletContext.tsxto expose anetworkMismatchboolean and surface it in the connect UI.Acceptance criteria
@stellar/freighter-api) each failure mode and confirm distinct, correct UI messaging.