diff options
| author | Adam Soltys <[email protected]> | 2026-06-19 00:09:21 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-19 00:09:21 -0700 |
| commit | 2f0e6d052efbca7f695dda942ab7da6221da3aa9 (patch) | |
| tree | c3c631549538785e3577f6af537238a28a1b429a /src/routes/(app)/invoice | |
| parent | 28cc6c706b0bd2b5322393dd3869e4161ec50423 (diff) | |
| download | coinos-ui-2f0e6d052efbca7f695dda942ab7da6221da3aa9.tar.gz coinos-ui-2f0e6d052efbca7f695dda942ab7da6221da3aa9.zip | |
receive/invoice: build POST body from snapshot, don't mutate $derived
The merchant receive and invoice pages mutated the $derived `invoice`
proxy (setType/setAmount/setMemo) then POSTed it. Mutating a $derived
and JSON.stringify-ing it serializes unreliably, so a stale type
(on-chain when lightning was expected) and a stale/10x-shifted amount
could leak from a prior interaction into POST /invoice (funk POS bug).
Build the body as { ...$state.snapshot(invoice), ...changes } so the
intended type/amount/address_type reliably win; update() takes the
plain body. Front-end only.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src/routes/(app)/invoice')
| -rw-r--r-- | src/routes/(app)/invoice/[id]/+page.svelte | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/src/routes/(app)/invoice/[id]/+page.svelte b/src/routes/(app)/invoice/[id]/+page.svelte index 29dd815d..a2a299bd 100644 --- a/src/routes/(app)/invoice/[id]/+page.svelte +++ b/src/routes/(app)/invoice/[id]/+page.svelte @@ -70,10 +70,10 @@ if ($amountPrompt && !amount) toggleAmount(); }); - let update = async () => { + let update = async (body) => { try { ({ id } = await post(`/invoice`, { - invoice, + invoice: body, user: { username, currency }, })); @@ -94,10 +94,12 @@ if (type === types.lightning && !amount && typeof newAmount === "undefined") goto(`/${username}/receive`, { invalidateAll: true, noScroll: true }); else { - if (typeof newAmount !== "undefined") invoice.amount = newAmount; - invoice.address_type = address_type; - invoice.type = type; - await update(); + // Build the POST body from a snapshot + explicit changes. Mutating the + // $derived `invoice` proxy and POSTing it serializes unreliably, leaking + // stale type/amount/hash from a prior interaction (see funk POS bug). + const body = { ...$state.snapshot(invoice), type, address_type }; + if (typeof newAmount !== "undefined") body.amount = newAmount; + await update(body); } settingType = false; }; @@ -113,10 +115,9 @@ settingAmount = false; if (typeof $amountPrompt === "undefined") $amountPrompt = true; - invoice.amount = newAmount; - invoice.tip = 0; + const body = { ...$state.snapshot(invoice), amount: newAmount, tip: 0 }; - await update(); + await update(body); }; let setMemo = async (e) => { @@ -124,8 +125,8 @@ e.stopPropagation(); settingMemo = false; - invoice.memo = memo; - await update(); + const body = { ...$state.snapshot(invoice), memo }; + await update(body); }; let settingMemo = $state(); |
