feat: add fixed float along with bitcoin maxi mode#2094
feat: add fixed float along with bitcoin maxi mode#2094im-adithya wants to merge 7 commits intomasterfrom
Conversation
📝 WalkthroughWalkthroughAdds Bitcoin Maxi Mode with localStorage-backed hook and settings toggle; introduces crypto swap UI (CryptoSwapAlert), integrates Fixed Float invoicing into receive/send flows, conditionally shows external swap/topup actions, and refactors on-chain receive to support Bitcoin and crypto swap paths. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant ReceiveOnchain as ReceiveOnchain Component
participant InvoiceAPI as Invoice API
participant FixedFloat as Fixed Float Service
participant AppState as App State / UI
User->>ReceiveOnchain: Select "Other Cryptocurrency" and submit
ReceiveOnchain->>InvoiceAPI: Create Invoice (CreateInvoiceRequest)
InvoiceAPI-->>ReceiveOnchain: Return Invoice Details (id, amount)
ReceiveOnchain->>FixedFloat: Open External URL (with Invoice ID)
FixedFloat-->>User: Present swap/payment UI
User->>FixedFloat: Complete crypto payment
FixedFloat->>InvoiceAPI: Notify/settle invoice
InvoiceAPI->>ReceiveOnchain: Invoice settled (via API/effect)
ReceiveOnchain->>AppState: Update transaction state / mark received
AppState-->>User: Display confirmation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/src/screens/wallet/Send.tsx (1)
75-106:⚠️ Potential issue | 🟡 MinorReset
showSwapAlerton retry/edit to avoid stale alert state.After Line [75], the alert stays visible even when the recipient is changed. Clear it on new submit attempts and input edits so the alert reflects current validation state.
💡 Suggested fix
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); + setShowSwapAlert(false); try { setLoading(true); if (validateBitcoinAddress(recipient)) { navigate(`/wallet/send/onchain`, { @@ placeholder="Invoice, lightning address, on-chain address" onChange={(e) => { setRecipient(e.target.value.trim()); + setShowSwapAlert(false); }} />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/screens/wallet/Send.tsx` around lines 75 - 106, The showSwapAlert state is left set true after a validation failure and isn't cleared on retries or when the recipient input changes; update the handlers that start new attempts to clear it by calling setShowSwapAlert(false) — specifically add setShowSwapAlert(false) at the start of the onSubmit handler (function onSubmit) and inside the recipient Input's onChange handler (where setRecipient is called) so editing the recipient or re-submitting resets the alert state.frontend/src/screens/wallet/receive/ReceiveOnchain.tsx (1)
281-284:⚠️ Potential issue | 🟠 MajorIncorrect link destination for "Receive Another Payment" button.
The button text says "Receive Another Payment" but it navigates to
/wallet/send. This should navigate to a receive-related path instead.Suggested fix
- <LinkButton to="/wallet/send" variant="outline" className="w-full"> + <LinkButton to="/wallet/receive" variant="outline" className="w-full"> <HandCoinsIcon className="w-4 h-4 mr-2" /> Receive Another Payment </LinkButton>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/screens/wallet/receive/ReceiveOnchain.tsx` around lines 281 - 284, The "Receive Another Payment" button uses LinkButton (and HandCoinsIcon) but wrongly navigates to "/wallet/send"; update the LinkButton's to prop to the appropriate receive route (e.g., "/wallet/receive" or the specific receive-onchain route used elsewhere) so the label matches the destination; ensure any tests or route constants referencing this path are updated to the chosen receive route.
🧹 Nitpick comments (1)
frontend/src/constants.ts (1)
13-13: Prefer numeric separators for satoshi constants.Optional readability tweak: align with the rest of this file’s numeric literal style (
10_000, etc.).♻️ Suggested tiny cleanup
-export const FIXED_FLOAT_MIN_SWAP_AMOUNT = 20000; +export const FIXED_FLOAT_MIN_SWAP_AMOUNT = 20_000;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/constants.ts` at line 13, Replace the integer literal for the constant FIXED_FLOAT_MIN_SWAP_AMOUNT with a numeric-separated form to match the file's style (e.g., 20_000) so the value remains the same but is easier to read alongside other constants like 10_000; update the export const FIXED_FLOAT_MIN_SWAP_AMOUNT declaration accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/components/CryptoSwapAlert.tsx`:
- Around line 18-21: In the AlertTitle JSX inside the CryptoSwapAlert component
(look for AlertTitle and CoinsIcon), fix the grammar by replacing the string
"Looking to pay to other Cryptocurrency?" with a corrected phrasing such as
"Looking to pay another cryptocurrency?" (use lowercase "cryptocurrency");
update the AlertTitle text accordingly to maintain consistent capitalization and
wording.
In `@frontend/src/screens/wallet/receive/ReceiveOnchain.tsx`:
- Around line 193-205: In ReceiveOnchain.tsx update the button label in the
ExternalLinkButton (the JSX inside ReceiveOnchain component) from "Topup using
other Cryptocurrency" to "Top up using other cryptocurrency" to fix the typo and
adjust capitalization; locate the ExternalLinkButton rendering near the
bitcoinMaxiMode conditional and replace the inner text accordingly.
- Around line 336-355: The POST to create an invoice is missing the required
CreateInvoiceRequest.description field and is currently bypassing types with an
unsafe assertion; update the payload in the request call inside the swapFrom ===
"crypto" branch (the CreateInvoiceRequest passed to request<Transaction> that
sets tx and calls setCryptoTransaction/openLink/toast) to include a descriptive
string (for example derived from swapAmount or a fixed "Receive on-chain"
message) so the body contains both amount and description and matches the
CreateInvoiceRequest type.
---
Outside diff comments:
In `@frontend/src/screens/wallet/receive/ReceiveOnchain.tsx`:
- Around line 281-284: The "Receive Another Payment" button uses LinkButton (and
HandCoinsIcon) but wrongly navigates to "/wallet/send"; update the LinkButton's
to prop to the appropriate receive route (e.g., "/wallet/receive" or the
specific receive-onchain route used elsewhere) so the label matches the
destination; ensure any tests or route constants referencing this path are
updated to the chosen receive route.
In `@frontend/src/screens/wallet/Send.tsx`:
- Around line 75-106: The showSwapAlert state is left set true after a
validation failure and isn't cleared on retries or when the recipient input
changes; update the handlers that start new attempts to clear it by calling
setShowSwapAlert(false) — specifically add setShowSwapAlert(false) at the start
of the onSubmit handler (function onSubmit) and inside the recipient Input's
onChange handler (where setRecipient is called) so editing the recipient or
re-submitting resets the alert state.
---
Nitpick comments:
In `@frontend/src/constants.ts`:
- Line 13: Replace the integer literal for the constant
FIXED_FLOAT_MIN_SWAP_AMOUNT with a numeric-separated form to match the file's
style (e.g., 20_000) so the value remains the same but is easier to read
alongside other constants like 10_000; update the export const
FIXED_FLOAT_MIN_SWAP_AMOUNT declaration accordingly.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
frontend/src/components/CryptoSwapAlert.tsxfrontend/src/components/PayLightningInvoice.tsxfrontend/src/constants.tsfrontend/src/hooks/useBitcoinMaxiMode.tsfrontend/src/screens/channels/CurrentChannelOrder.tsxfrontend/src/screens/channels/first/FirstChannel.tsxfrontend/src/screens/settings/Settings.tsxfrontend/src/screens/wallet/Receive.tsxfrontend/src/screens/wallet/Send.tsxfrontend/src/screens/wallet/receive/ReceiveOnchain.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
frontend/src/screens/wallet/Send.tsx (2)
28-31:⚠️ Potential issue | 🟡 MinorReset
showSwapAlertin paste flow too.You clear the alert on manual edits (Line 106), but not when the recipient is replaced via clipboard paste. This can leave a stale warning visible.
Small consistency fix
const paste = async () => { const text = await navigator.clipboard.readText(); setRecipient(text.trim()); + setShowSwapAlert(false); };Also applies to: 104-107
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/screens/wallet/Send.tsx` around lines 28 - 31, The paste handler (paste) sets recipient from the clipboard but doesn't clear the swap warning; update the paste function to also call setShowSwapAlert(false) after setRecipient(text.trim()) so the stale swap alert is cleared when recipients are pasted; similarly ensure any other clipboard-based recipient setters use setShowSwapAlert(false) (e.g., the handler referenced around the manual-edit clearing in the recipient change path).
74-79:⚠️ Potential issue | 🟠 MajorOnly show the swap alert for parse/validation failures, not every exception.
Line 75 currently enables the swap prompt for all errors, including LNURL fetch/network failures. That can misdirect users toward swapping when the recipient is actually valid but temporarily unresolved.
Proposed tightening of error classification
- } catch (error) { - setShowSwapAlert(true); - toast.error("Invalid recipient", { - description: "" + error, - }); - console.error(error); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + const isInvalidRecipient = + /invalid|invoice|bolt11|recipient/i.test(message); + + setShowSwapAlert(isInvalidRecipient); + toast.error( + isInvalidRecipient ? "Invalid recipient" : "Could not resolve recipient", + { description: message } + ); + console.error(error); } finally {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/screens/wallet/Send.tsx` around lines 74 - 79, The catch block in Send.tsx currently calls setShowSwapAlert(true) for every exception (see the catch handling that also calls toast.error), which wrongly prompts a swap on network/LNURL failures; update the catch to classify errors and only enable setShowSwapAlert(true) for parse/validation-type failures (e.g., errors whose type/name/message indicates "parse", "validation", "Invalid recipient", or a specific ParseError/ValidationError your codebase throws), while for network/LNURL/fetch failures just show the toast.error and log the error; keep the existing toast.error and console.error behavior but guard the setShowSwapAlert call so it runs only for the identified recipient-parse/validation cases (refer to setShowSwapAlert and toast.error in the Send.tsx catch block).frontend/src/screens/wallet/receive/ReceiveOnchain.tsx (1)
381-412:⚠️ Potential issue | 🟠 MajorDecouple Fixed Float flow from
swapInfoavailability and limits.
swapInfois required globally (Line [381]) andswapInfo.maxAmountis always enforced (Line [409]-Line [412]), but the crypto path submits to/api/invoicesdirectly. This can block/over-restrict Fixed Float receive when swap-in metadata is unavailable or more restrictive.Proposed fix
- if (!info || !balances || !swapInfo || (!recommendedFees && !mempoolError)) { + if (!info || !balances || (!recommendedFees && !mempoolError)) { return <Loading />; } + const receivableMax = (balances.lightning.totalReceivable / 1000) * 0.99; + const amountMax = + swapFrom === "bitcoin" + ? Math.min(swapInfo?.maxAmount ?? receivableMax, receivableMax) + : receivableMax; ... - max={Math.min( - swapInfo.maxAmount, - (balances.lightning.totalReceivable / 1000) * 0.99 - )} + max={amountMax}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/screens/wallet/receive/ReceiveOnchain.tsx` around lines 381 - 412, The component currently requires swapInfo and always enforces swapInfo.maxAmount, which blocks the Fixed Float / crypto flow; update the top loading guard and the Amount input bounds so the crypto/Fixed Float path does not depend on swapInfo. Specifically, change the initial check that returns <Loading /> so it does not require swapInfo when swapFrom === "crypto" (or when isCryptoReceiveState is true), and in the InputWithAdornment props use conditional min/max: when swapFrom === "bitcoin" use swapInfo.minAmount / swapInfo.maxAmount, otherwise use FIXED_FLOAT_MIN_SWAP_AMOUNT and the appropriate Fixed Float max (or leave max undefined) so the crypto/invoice submission path (onSubmit -> /api/invoices) is not constrained by missing or restrictive swapInfo; update references to swapInfo, swapFrom, isCryptoReceiveState, FIXED_FLOAT_MIN_SWAP_AMOUNT, InputWithAdornment, and onSubmit accordingly.
🧹 Nitpick comments (1)
frontend/src/components/connections/SuggestedAppData.tsx (1)
194-256: Incomplete wording alignment within this entry.The PR objective is to "align top up wording everywhere," but there are still inconsistencies within this same
2fiatentry:
- Line 200:
extendedDescriptionuses "top-ups" (hyphenated)- Line 248:
finalizeGuidestill uses "2fiat topup" (one word)Consider updating these to match the "top up" (two words) convention used in the changed lines.
Proposed fix
extendedDescription: - "No-KYC virtual prepaid Mastercard. Anonymous payments, Instant lightning top-ups, Apple & Google Pay ready, Load amounts from $10 to $10,000, All cards support 3D Secure (3DS), Global usage - pay anywhere Mastercard is accepted.", + "No-KYC virtual prepaid Mastercard. Anonymous payments, Instant lightning top ups, Apple & Google Pay ready, Load amounts from $10 to $10,000, All cards support 3D Secure (3DS), Global usage - pay anywhere Mastercard is accepted.",<li> - Click the "Connect Wallet" button inside the 2fiat topup app, + Click the "Connect Wallet" button inside the 2fiat top up app, choose "Alby Hub {"->"} Connection Secret" and paste the connection secret. </li>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/connections/SuggestedAppData.tsx` around lines 194 - 256, Update the inconsistent "top up" wording in the 2fiat entry: change the hyphenated "top-ups" inside the extendedDescription to "top up" and change the "2fiat topup" phrase inside installGuide/finalizeGuide to "2fiat top up" so all occurrences match the "top up" two-word convention; locate these strings in the SuggestedAppData.tsx 2fiat object (fields: extendedDescription, installGuide, finalizeGuide, and any webLink/display text) and replace them accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/screens/ConnectAlbyAccount.tsx`:
- Line 86: The CardTitle text "Fiat Top ups" in ConnectAlbyAccount.tsx uses
inconsistent capitalization; update the CardTitle content (component: CardTitle)
to use title case or hyphenation to match other titles—e.g., change to "Fiat Top
Ups" or "Fiat Top-Ups"—so the displayed card title is consistent with other
headings like "Lightning Address" and "Email Notifications".
---
Outside diff comments:
In `@frontend/src/screens/wallet/receive/ReceiveOnchain.tsx`:
- Around line 381-412: The component currently requires swapInfo and always
enforces swapInfo.maxAmount, which blocks the Fixed Float / crypto flow; update
the top loading guard and the Amount input bounds so the crypto/Fixed Float path
does not depend on swapInfo. Specifically, change the initial check that returns
<Loading /> so it does not require swapInfo when swapFrom === "crypto" (or when
isCryptoReceiveState is true), and in the InputWithAdornment props use
conditional min/max: when swapFrom === "bitcoin" use swapInfo.minAmount /
swapInfo.maxAmount, otherwise use FIXED_FLOAT_MIN_SWAP_AMOUNT and the
appropriate Fixed Float max (or leave max undefined) so the crypto/invoice
submission path (onSubmit -> /api/invoices) is not constrained by missing or
restrictive swapInfo; update references to swapInfo, swapFrom,
isCryptoReceiveState, FIXED_FLOAT_MIN_SWAP_AMOUNT, InputWithAdornment, and
onSubmit accordingly.
In `@frontend/src/screens/wallet/Send.tsx`:
- Around line 28-31: The paste handler (paste) sets recipient from the clipboard
but doesn't clear the swap warning; update the paste function to also call
setShowSwapAlert(false) after setRecipient(text.trim()) so the stale swap alert
is cleared when recipients are pasted; similarly ensure any other
clipboard-based recipient setters use setShowSwapAlert(false) (e.g., the handler
referenced around the manual-edit clearing in the recipient change path).
- Around line 74-79: The catch block in Send.tsx currently calls
setShowSwapAlert(true) for every exception (see the catch handling that also
calls toast.error), which wrongly prompts a swap on network/LNURL failures;
update the catch to classify errors and only enable setShowSwapAlert(true) for
parse/validation-type failures (e.g., errors whose type/name/message indicates
"parse", "validation", "Invalid recipient", or a specific
ParseError/ValidationError your codebase throws), while for network/LNURL/fetch
failures just show the toast.error and log the error; keep the existing
toast.error and console.error behavior but guard the setShowSwapAlert call so it
runs only for the identified recipient-parse/validation cases (refer to
setShowSwapAlert and toast.error in the Send.tsx catch block).
---
Nitpick comments:
In `@frontend/src/components/connections/SuggestedAppData.tsx`:
- Around line 194-256: Update the inconsistent "top up" wording in the 2fiat
entry: change the hyphenated "top-ups" inside the extendedDescription to "top
up" and change the "2fiat topup" phrase inside installGuide/finalizeGuide to
"2fiat top up" so all occurrences match the "top up" two-word convention; locate
these strings in the SuggestedAppData.tsx 2fiat object (fields:
extendedDescription, installGuide, finalizeGuide, and any webLink/display text)
and replace them accordingly.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
frontend/src/components/connections/SuggestedAppData.tsxfrontend/src/screens/ConnectAlbyAccount.tsxfrontend/src/screens/channels/CurrentChannelOrder.tsxfrontend/src/screens/wallet/Send.tsxfrontend/src/screens/wallet/receive/ReceiveOnchain.tsx
| <CardHeader className="flex flex-col justify-center items-center text-center p-4"> | ||
| <CreditCardIcon className="size-6" /> | ||
| <CardTitle className="text-sm">Fiat Topups</CardTitle> | ||
| <CardTitle className="text-sm">Fiat Top ups</CardTitle> |
There was a problem hiding this comment.
Inconsistent capitalization in card title.
"Fiat Top ups" has mixed casing ("Top" capitalized, "ups" lowercase). For consistency with other card titles using title case (e.g., "Lightning Address", "Email Notifications"), consider "Fiat Top Ups" or "Fiat Top-Ups".
✏️ Suggested fix
- <CardTitle className="text-sm">Fiat Top ups</CardTitle>
+ <CardTitle className="text-sm">Fiat Top-Ups</CardTitle>📝 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.
| <CardTitle className="text-sm">Fiat Top ups</CardTitle> | |
| <CardTitle className="text-sm">Fiat Top-Ups</CardTitle> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/src/screens/ConnectAlbyAccount.tsx` at line 86, The CardTitle text
"Fiat Top ups" in ConnectAlbyAccount.tsx uses inconsistent capitalization;
update the CardTitle content (component: CardTitle) to use title case or
hyphenation to match other titles—e.g., change to "Fiat Top Ups" or "Fiat
Top-Ups"—so the displayed card title is consistent with other headings like
"Lightning Address" and "Email Notifications".
|
Should we add to http://localhost:5173/wallet/swap too? |
To keep it simple, we could redirect to http://localhost:5173/wallet/receive/onchain with "Other Cryptocurrency" selected |
|
Hmmm I was thinking to do that once we have a proper fixed float swap service running in the backend, but yeah it makes sense to add it in swaps as more people might find out 👍 |
@im-adithya weird bug |
Ah, it's not a bug. I didn't read the warning above. I should have selected "To On-Chain balance" |
| <div className="border-t pt-4 text-sm grid gap-2"> | ||
| <div className="flex items-center justify-between"> | ||
| <Label>Swap Fee</Label> | ||
| <p className="text-muted-foreground">0.5%-1% + on-chain fees</p> |
There was a problem hiding this comment.
this should be 1% because to lightning we have to use the fixed option
|
@im-adithya can we add it to this page too? http://localhost:5173/channels/onchain/deposit-bitcoin |
|
@im-adithya should we add a secondary option at the bottom "withdraw to other cryptocurrency"? http://localhost:5173/wallet/withdraw |
| <h3 className="text-xl font-medium">Experience</h3> | ||
| <div className="flex items-center justify-between max-w-md rounded-lg border p-3"> | ||
| <div className="grid gap-2"> | ||
| <Label htmlFor="bitcoin-maxi-mode">Bitcoin Maxi mode</Label> |
There was a problem hiding this comment.
should we add a followup issue for "Hide fiat"? as another option inside this maxi mode section?




Fixes #2071
Description
Adds fixed float option and bitcoin maxi mode to disable those suggestions in settings
Video
Screen.Recording.2026-02-26.at.5.08.18.PM.mov
Summary by CodeRabbit
New Features
Style