web(WalletStatus): display locked badge when extension wallet is locked - #555
Conversation
Detect stellar-wallets-kit locked/empty-address error code (-3) and unlock messages so WalletStatus renders a Locked badge instead of the generic disconnected Connect CTA. Closes Fundable-Protocol#393
|
@muizbolaji4 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
📝 WalkthroughWalkthroughAdded locked-wallet error detection, provider state handling, and a ChangesLocked wallet status
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant WalletExtension
participant StellarWalletProvider
participant ConnectButton
participant WalletStatus
WalletExtension->>StellarWalletProvider: Return locked-wallet error
StellarWalletProvider->>StellarWalletProvider: Set connectionStatus to locked
StellarWalletProvider->>ConnectButton: Expose isLocked
ConnectButton->>WalletStatus: Render Locked badge
WalletStatus->>StellarWalletProvider: Open wallet modal on click
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/web/src/components/molecules/WalletStatus.test.tsx (1)
16-29: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the Locked badge opens the retry modal.
The test passes if
onClick={openModal}is removed. Keep anopenModalmock reference, click the labeled button, and assert it was called once.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/components/molecules/WalletStatus.test.tsx` around lines 16 - 29, Update the locked-wallet test around WalletStatus to retain a named openModal mock, click the labeled locked-wallet button, and assert the mock is called exactly once; keep the existing Locked status assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/utils/wallet-errors.ts`:
- Around line 23-25: Update the error classification logic around the
WalletErrorLike normalization to inspect both the top-level err.message and
nested err.error?.message instead of allowing a generic wrapper message to mask
the nested message. Preserve code extraction, ensure either normalized message
can trigger the appropriate classification, and add a regression case for a
wrapper containing “RPC failed” with nested code -3 and “Getting the address...”
message.
---
Nitpick comments:
In `@apps/web/src/components/molecules/WalletStatus.test.tsx`:
- Around line 16-29: Update the locked-wallet test around WalletStatus to retain
a named openModal mock, click the labeled locked-wallet button, and assert the
mock is called exactly once; keep the existing Locked status assertions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 55ec5fd3-21c0-46ea-b6c5-e15e1dbdc7c8
📒 Files selected for processing (6)
apps/web/src/components/molecules/WalletStatus.test.tsxapps/web/src/components/molecules/WalletStatus.tsxapps/web/src/components/organisms/connect-button.tsxapps/web/src/providers/StellarWalletProvider.tsxapps/web/src/utils/wallet-errors.test.tsapps/web/src/utils/wallet-errors.ts
| const err = error as WalletErrorLike; | ||
| const code = err.code ?? err.error?.code; | ||
| const message = String(err.message ?? err.error?.message ?? "").toLowerCase(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Inspect both wrapper and nested error messages.
A generic top-level message masks error.message, so { message: "RPC failed", error: { code: -3, message: "Getting the address..." } } is misclassified and the provider falls back to the generic disconnected flow. Normalize and inspect both messages; add this wrapper shape as a regression case.
Proposed fix
- const message = String(err.message ?? err.error?.message ?? "").toLowerCase();
+ const messages = [err.message, err.error?.message]
+ .map((value) => String(value ?? "").toLowerCase());
+
+ const hasLockedMessage = messages.some(
+ (message) =>
+ message.includes("locked") || message.includes("unlock"),
+ );
- if (
- message.includes("locked") ||
- message.includes("unlock") ||
- message.includes("wallet is locked")
- ) {
+ if (hasLockedMessage) {
return true;
}
- if (code === WALLET_LOCKED_ERROR_CODE && message.includes("address")) {
+ if (
+ code === WALLET_LOCKED_ERROR_CODE &&
+ messages.some((message) => message.includes("address"))
+ ) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const err = error as WalletErrorLike; | |
| const code = err.code ?? err.error?.code; | |
| const message = String(err.message ?? err.error?.message ?? "").toLowerCase(); | |
| const err = error as WalletErrorLike; | |
| const code = err.code ?? err.error?.code; | |
| const messages = [err.message, err.error?.message] | |
| .map((value) => String(value ?? "").toLowerCase()); | |
| const hasLockedMessage = messages.some( | |
| (message) => | |
| message.includes("locked") || message.includes("unlock"), | |
| ); | |
| if (hasLockedMessage) { | |
| return true; | |
| } | |
| if ( | |
| code === WALLET_LOCKED_ERROR_CODE && | |
| messages.some((message) => message.includes("address")) | |
| ) { | |
| return true; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/utils/wallet-errors.ts` around lines 23 - 25, Update the error
classification logic around the WalletErrorLike normalization to inspect both
the top-level err.message and nested err.error?.message instead of allowing a
generic wrapper message to mask the nested message. Preserve code extraction,
ensure either normalized message can trigger the appropriate classification, and
add a regression case for a wrapper containing “RPC failed” with nested code -3
and “Getting the address...” message.
|
dont forget to offramp using https://stellar.fundable.finance/offramp its fast, free and p2p rates |
Overview
This PR fixes locked extension wallets showing as a generic disconnected state. When connect fails with the stellar-wallets-kit locked/empty-address error code (
-3) or unlock-related messages, the UI now surfaces a dedicated Locked badge viaWalletStatus.Related Issue
Closes #393
Changes
🔒 Locked wallet detection
[ADD]
apps/web/src/utils/wallet-errors.tsWALLET_LOCKED_ERROR_CODE(-3) matching@creit.tech/stellar-wallets-kitFreighter empty-address errors.isLockedWalletError()detects code-3address errors and locked/unlock message patterns.[MODIFY]
apps/web/src/providers/StellarWalletProvider.tsxConnectionStatuswith"locked".isLockedon wallet context.connectionStatusto"locked"when a locked-wallet error is detected (instead of falling back to idle/disconnected).🏷️ WalletStatus badge
[ADD]
apps/web/src/components/molecules/WalletStatus.tsxisLocked— lines 15–35 implement the locked-state UI from the issue.[MODIFY]
apps/web/src/components/organisms/connect-button.tsxWalletStatusLocked badge instead of the generic CONNECT WALLET CTA when the extension is locked.✅ Tests
apps/web/src/utils/wallet-errors.test.tsapps/web/src/components/molecules/WalletStatus.test.tsxVerification Results
WalletStatus.tsx:15-35(locked badge)isLocked-3+ unlock/locked messagesMade with Cursor
Summary by CodeRabbit
New Features
Bug Fixes
Tests