diff options
| author | Adam Soltys <[email protected]> | 2026-02-28 22:06:27 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-28 22:06:27 -0800 |
| commit | 6ca9170a25b253483e7ce15767b7daae67c1334f (patch) | |
| tree | 38be88205312e504630dc84c5ab0223a4f7cff6a /src | |
| parent | 36ae7b0cfc66aa614287f96ac2be85ff183130a2 (diff) | |
| download | coinos-ui-6ca9170a25b253483e7ce15767b7daae67c1334f.tar.gz coinos-ui-6ca9170a25b253483e7ce15767b7daae67c1334f.zip | |
ark wait for send
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Account.svelte | 30 | ||||
| -rw-r--r-- | src/lib/ark.ts | 62 | ||||
| -rw-r--r-- | src/lib/socket.ts | 3 | ||||
| -rw-r--r-- | src/routes/(app)/+layout.svelte | 6 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.server.ts | 2 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.svelte | 26 |
7 files changed, 86 insertions, 45 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte index ff9218fe..66b1cf12 100644 --- a/src/components/Account.svelte +++ b/src/components/Account.svelte @@ -129,14 +129,14 @@ {/if} </div> <div class="flex items-center gap-1 shrink-0 text-base-content"> - <a - href="/payments" - class="hover:text-gray-800 w-10 h-10 flex items-center justify-center" - aria-label="Payment history" - onclick={(e) => setAccount(e, "/payments")} - > - <iconify-icon noobserver icon="ph:clock-counter-clockwise-bold" width="38"></iconify-icon> - </a> + <!-- <a --> + <!-- href="/payments" --> + <!-- class="hover:text-gray-800 w-10 h-10 flex items-center justify-center" --> + <!-- aria-label="Payment history" --> + <!-- onclick={(e) => setAccount(e, "/payments")} --> + <!-- > --> + <!-- <iconify-icon noobserver icon="ph:clock-counter-clockwise-bold" width="38"></iconify-icon> --> + <!-- </a> --> <a href={`/account/${id}`} class="hover:opacity-80 relative w-10 h-10 flex items-center justify-center" @@ -152,12 +152,12 @@ {:else} <img src="/images/icon.png" class="w-8 h-8" alt="Coinos" /> {/if} - <iconify-icon - noobserver - icon="ph:gear-bold" - width="20" - class="absolute -bottom-1 -right-1 text-base-content bg-base-100 rounded-full" - ></iconify-icon> + <!-- <iconify-icon --> + <!-- noobserver --> + <!-- icon="ph:faders-bold" --> + <!-- width="20" --> + <!-- class="absolute -bottom-1 -right-1 text-base-content bg-base-100 rounded-full" --> + <!-- ></iconify-icon> --> </a> </div> </div> @@ -172,7 +172,7 @@ </a> <a href={`/send`} class="contents" onclick={(e) => setAccount(e, "/send")}> - <button type="button" class="btn btn-accent !w-auto flex-1"> + <button type="button" class="btn !w-auto flex-1"> <iconify-icon noobserver icon="ph:paper-plane-right-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.dashboard.send")}</div> </button> diff --git a/src/lib/ark.ts b/src/lib/ark.ts index 75609381..b59baa04 100644 --- a/src/lib/ark.ts +++ b/src/lib/ark.ts @@ -338,6 +338,8 @@ export const addProcessedVtxos = (keys: string[]) => { // Flag to suppress sync during sends export let arkSending = false; +// Flag to suppress "Received" toasts during vault forward sends +export let vaultForwarding = false; let syncPromise: Promise<any> | null = null; const withTimeout = <T>(promise: Promise<T>, ms: number, label: string) => @@ -392,27 +394,36 @@ export const sendArk = async (address: string, amount: number) => { } } - // Verify the send actually changed the balance - const postBalance = await sendWallet.getBalance(); - const postSendTotal = (postBalance.available || 0) + (postBalance.preconfirmed || 0); - console.log( - "ark send: pre-balance", - preSendTotal, - "post-balance", - postSendTotal, - "amount", - amount, - "txid", - txid, - ); - if (postSendTotal >= preSendTotal) { - throw new Error("Send failed: balance unchanged after sendBitcoin"); + // Verify the send and mark VTXOs as processed, but don't let + // stalled SDK calls block the flow — the send already succeeded + try { + const postBalance: any = await withTimeout(sendWallet.getBalance(), 10_000, "post-send getBalance"); + const postSendTotal = (postBalance.available || 0) + (postBalance.preconfirmed || 0); + console.log( + "ark send: pre-balance", + preSendTotal, + "post-balance", + postSendTotal, + "amount", + amount, + "txid", + txid, + ); + if (postSendTotal >= preSendTotal) { + console.warn("ark send: balance unchanged, but txid was returned — proceeding"); + } + } catch (e: any) { + console.warn("ark send: post-send balance check failed:", e.message); } // Mark post-send VTXOs as processed so notifyIncomingFunds // ignores change VTXOs from this send - const vtxos = await sendWallet.getVtxos({ spendableOnly: false }); - if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); + try { + const vtxos: any[] = await withTimeout(sendWallet.getVtxos({ spendableOnly: false }), 10_000, "post-send getVtxos"); + if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); + } catch (e: any) { + console.warn("ark send: post-send getVtxos failed:", e.message); + } return txid; } finally { @@ -433,16 +444,21 @@ export const sendArkViaForward = async ({ forward?: string; user: any; }) => { - const txid = await sendArk(serverArkAddress, amount); + vaultForwarding = true; + try { + const txid = await sendArk(serverArkAddress, amount); - await post("/post/ark/vault-send", { hash: txid, amount, aid }); + await post("/post/ark/vault-send", { hash: txid, amount, aid }); - const invoice: any = { type: "ark", amount, aid }; - if (forward) invoice.forward = forward; + const invoice: any = { type: "ark", amount, aid }; + if (forward) invoice.forward = forward; - const inv = await post("/post/invoice", { invoice, user }); + const inv = await post("/post/invoice", { invoice, user }); - return post("/post/ark/receive", { amount, hash: txid, iid: inv.id }); + return await post("/post/ark/receive", { amount, hash: txid, iid: inv.id }); + } finally { + vaultForwarding = false; + } }; export const refresh = async () => { diff --git a/src/lib/socket.ts b/src/lib/socket.ts index 3e71e1ce..46784503 100644 --- a/src/lib/socket.ts +++ b/src/lib/socket.ts @@ -1,6 +1,7 @@ import { goto, invalidate } from "$app/navigation"; import { navigating, page } from "$app/stores"; import { PUBLIC_SOCKET } from "$env/static/public"; +import { vaultForwarding } from "$lib/ark"; import { event, importing, invoice, last, lastPayment, paymentSignal, request } from "$lib/store"; import { s, sleep, success, wait } from "$lib/utils"; import cookies from "js-cookie"; @@ -62,7 +63,7 @@ export const messages = (data) => ({ const username = cookies.get("username"); - if (amount > 0) { + if (amount > 0 && !vaultForwarding) { if ( pathname.includes(`/${username}`) || pathname.includes("/receive") || diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index a7224a15..c04dc6f9 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { getWallet, subscribeToAsp, syncTransactions, settle, refresh, arkkey, arkaid, sendArk, arkSending, autoUnlockArk, getServiceWorkerWallet, cleanupServiceWorkerWallet } from "$lib/ark"; + import { getWallet, subscribeToAsp, syncTransactions, settle, refresh, arkkey, arkaid, sendArk, arkSending, vaultForwarding, autoUnlockArk, getServiceWorkerWallet, cleanupServiceWorkerWallet } from "$lib/ark"; import { SvelteToast } from "@zerodevx/svelte-toast"; import { onDestroy, onMount } from "svelte"; import { close, connect, send, socket } from "$lib/socket"; @@ -77,7 +77,7 @@ } finally { arkForwarding = false; } - } else if (result?.received > 0) { + } else if (result?.received > 0 && !vaultForwarding) { const paidPayment = result.payments?.find((p: any) => p.iid && p.amount > 0); if (paidPayment) { goto(`/invoice/${paidPayment.iid}`); @@ -117,7 +117,7 @@ await new Promise((r) => setTimeout(r, delay)); const aid = $arkaid || getCookie("aid") || user.id; const result = await syncTransactions(aid); - if (result?.received > 0) { + if (result?.received > 0 && !vaultForwarding) { const paidPayment = result.payments?.find((p: any) => p.iid && p.amount > 0); if (paidPayment) { goto(`/invoice/${paidPayment.iid}`); diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index f2f1fd46..a234854d 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -120,7 +120,7 @@ {#each accounts as account} <Account {user} {rates} {account} /> {/each} - <button class="btn btn-accent w-full" onclick={addAccount}> + <button class="btn w-full" onclick={addAccount}> {#if adding} <Spinner /> {:else} diff --git a/src/routes/(static)/login/+page.server.ts b/src/routes/(static)/login/+page.server.ts index 68143d83..0c493422 100644 --- a/src/routes/(static)/login/+page.server.ts +++ b/src/routes/(static)/login/+page.server.ts @@ -66,7 +66,7 @@ export const actions = { if (res.status === 401) { if (text.startsWith("2fa")) throw new Error("2fa"); - throw new Error(text); + return fail(400, { error: "Login failed" }); } if (!res.ok) { diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte index c23acc8b..20b56134 100644 --- a/src/routes/(static)/login/+page.svelte +++ b/src/routes/(static)/login/+page.svelte @@ -161,7 +161,31 @@ await invalidateAll(); goto(result.data?.redirectUrl || `/${uname}`); } else { - applyAction(result); + // Challenge-response failed — fall back to password-based login + console.log("Auth key login failed, falling back to password login"); + formData.set("authPubkey", pubkey); + const fallbackRes = await fetch("/login?/login", { + method: "POST", + body: formData, + }); + const fallbackResult: any = deserialize(await fallbackRes.text()); + if (fallbackResult.type === "success") { + try { + const oldPrfKey = await deriveWalletEntropy(sk); + await resolveCanonicalKey( + passwordMethodId(), + sk.buffer as ArrayBuffer, + fallbackResult.data?.encryptedKeys, + oldPrfKey, + ); + } catch (e) { + console.log("Canonical key resolution failed", e); + } + await invalidateAll(); + goto(fallbackResult.data?.redirectUrl || `/${uname}`); + } else { + applyAction(fallbackResult); + } } return; } |
