diff options
| author | Adam Soltys <[email protected]> | 2026-02-14 15:46:09 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-14 15:46:09 -0800 |
| commit | 40fc5fe98c08357dff41539de48532d554aa73cb (patch) | |
| tree | 289e6f1af7f256b1e8ddab75d74e272ead7baa2f /src | |
| parent | d242a387279119cfc6e191eff3b4e2228cbb5a4e (diff) | |
| download | coinos-ui-40fc5fe98c08357dff41539de48532d554aa73cb.tar.gz coinos-ui-40fc5fe98c08357dff41539de48532d554aa73cb.zip | |
custodial ark sends
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Account.svelte | 2 | ||||
| -rw-r--r-- | src/components/InvoiceActions.svelte | 2 | ||||
| -rw-r--r-- | src/components/InvoiceTypes.svelte | 17 | ||||
| -rw-r--r-- | src/lib/ark.ts | 14 | ||||
| -rw-r--r-- | src/locales/en.json | 6 | ||||
| -rw-r--r-- | src/routes/(app)/+layout.svelte | 21 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+page.svelte | 17 | ||||
| -rw-r--r-- | src/routes/(app)/account/[id]/+page.svelte | 26 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/+page.svelte | 2 |
9 files changed, 68 insertions, 39 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte index b077c30b..adea5c70 100644 --- a/src/components/Account.svelte +++ b/src/components/Account.svelte @@ -146,7 +146,7 @@ </div> {/if} </div> - <div class="flex items-start gap-4 shrink-0 text-gray-600"> + <div class="flex items-start gap-4 shrink-0 text-black"> <div class="flex items-center justify-center w-8 h-8 leading-[0]"> {#if isArk} <img src="/images/ark.png" class="w-8 h-8 rounded-full object-cover" alt="Ark" /> diff --git a/src/components/InvoiceActions.svelte b/src/components/InvoiceActions.svelte index 53447fec..e7fb57e3 100644 --- a/src/components/InvoiceActions.svelte +++ b/src/components/InvoiceActions.svelte @@ -90,7 +90,7 @@ </button> {/if} - {#if !account?.seed && !(account?.pubkey && account?.fingerprint)} + {#if !account?.seed && !(account?.pubkey && account?.fingerprint) && account?.type !== "ark"} <button class="btn flex-nowrap !w-auto grow" class:bg-base-300={type === types.bitcoin} diff --git a/src/components/InvoiceTypes.svelte b/src/components/InvoiceTypes.svelte index 5845f699..23735a49 100644 --- a/src/components/InvoiceTypes.svelte +++ b/src/components/InvoiceTypes.svelte @@ -71,7 +71,7 @@ }} > <div class="bg-black rounded-full w-8 h-8 items-center justify-center flex"> - <div class="m-auto"> + <div class="m-auto mt-1"> <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300 text-2xl" ></iconify-icon> </div> @@ -86,7 +86,7 @@ onclick={() => (activeOnly ? toggleType() : setType(types.bolt12))} > <div class="bg-black rounded-full w-8 h-8 items-center justify-center flex"> - <div class="m-auto"> + <div class="m-auto mt-1"> <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300 text-2xl" ></iconify-icon> </div> @@ -110,7 +110,7 @@ }} > <div class="bg-black rounded-full w-8 h-8 items-center justify-center flex"> - <div class="m-auto"> + <div class="m-auto mt-1"> <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300 text-2xl" ></iconify-icon> </div> @@ -142,6 +142,17 @@ <img src="/images/liquid.svg" class="w-8" alt="Liquid" /> <div class="my-auto text-lg">Liquid</div> </button> + + <button + class="btn flex-nowrap !w-auto grow" + class:bg-base-300={type === types.ark} + class:text-secondary={type === types.ark} + class:hidden={activeOnly && type !== types.ark} + onclick={() => (activeOnly ? toggleType() : setType("ark"))} + > + <img src="/images/ark.png" class="w-8 rounded-full" alt="Ark" /> + <div class="my-auto text-lg">Ark</div> + </button> </div> <div></div> diff --git a/src/lib/ark.ts b/src/lib/ark.ts index b9902a5a..dcc42868 100644 --- a/src/lib/ark.ts +++ b/src/lib/ark.ts @@ -125,7 +125,19 @@ export const sendArk = async (address: string, amount: number) => { arkSending = true; try { - const txid = await wallet.sendBitcoin({ address, amount }); + let txid; + try { + txid = await wallet.sendBitcoin({ address, amount }); + } catch (e: any) { + if (e?.message?.includes("VTXO_ALREADY_REGISTERED")) { + await wallet.settle(); + const vtxos = await wallet.getVtxos({ spendableOnly: false }); + if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); + txid = await wallet.sendBitcoin({ address, amount }); + } else { + throw e; + } + } // Mark post-send VTXOs as processed so notifyIncomingFunds // ignores change VTXOs from this send diff --git a/src/locales/en.json b/src/locales/en.json index 9f23dd47..2ed0d54d 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -53,7 +53,7 @@ "revealMnemonic": "Reveal seed phrase", "regenerate": "Regenerate", "deleteAccount": "Delete account", - "addAccount": "Create a non-custodial account", + "addAccount": "Add account", "create": "Create", "import": "Import", "accountSetup": "Account setup", @@ -101,7 +101,7 @@ "dm": { "chatHeader": "Chats", "newChatHeader": "New Chat", - "header": "Direct Messages", + "header": "Messages", "searchPrompt": "username, nip-05 or pubkey", "findByUsername": "Find by username", "findByNIP05": "Find by NIP-05", @@ -244,7 +244,7 @@ "light": "Light", "about": "About", "docs": "Docs", - "dm": "Nostr Messages", + "dm": "Messages", "messages": "Messages", "funds": "Funds", "map": "Map", diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 2c96fc7c..2d252385 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { getWallet, syncTransactions, settle, arkkey, arkaid } from "$lib/ark"; + import { getWallet, syncTransactions, settle, arkkey, arkaid, sendArk } from "$lib/ark"; import { SvelteToast } from "@zerodevx/svelte-toast"; import { onDestroy, onMount } from "svelte"; import { close, connect, send, socket } from "$lib/socket"; @@ -22,7 +22,7 @@ import AppHeader from "$comp/AppHeader.svelte"; import Nostr from "$comp/Nostr.svelte"; import Password from "$comp/Password.svelte"; - import { s, f, toFiat, success, getCookie, warning } from "$lib/utils"; + import { s, f, toFiat, success, getCookie, warning, post } from "$lib/utils"; import { t, locale, loading } from "$lib/translations"; import { goto, invalidate, afterNavigate, preloadData } from "$app/navigation"; @@ -52,6 +52,7 @@ }); let arkSyncing = false; + let arkForwarding = false; let arkSync = async () => { if (arkSyncing) return; @@ -61,11 +62,23 @@ const aid = $arkaid || getCookie("aid") || user.id; const result = await syncTransactions(aid); - if (result?.received > 0) { + if (result?.forward && !arkForwarding) { + arkForwarding = true; + try { + const { serverArkAddress, amount, iid } = result.forward; + const txid = await sendArk(serverArkAddress, amount); + await post("/post/ark/vault-send", { hash: txid, amount, aid }); + await post("/post/ark/receive", { amount, hash: txid, iid }); + } catch (e) { + console.error("Ark custodial forward failed:", e); + } finally { + arkForwarding = false; + } + } else if (result?.received > 0) { if ($fiat && $rateStore && user?.currency) { success(`Received ${f(toFiat(result.received, $rateStore as number), user.currency)}!`); } else { - success(`Received ⚡️${s(result.received)}!`); + success(`Received ${s(result.received)}!`); } } diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index 966925d5..4885189b 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -64,17 +64,12 @@ {#each accounts as account} <Account {user} {rates} {account} /> {/each} - <div class="flex justify-end"> - <a href="/account/new" class="contents" aria-label={$t("accounts.addAccount")}> - <button - class="btn btn-circle btn-accent !w-14 !h-14 !rounded-full" - aria-label={$t("accounts.addAccount")} - title={$t("accounts.addAccount")} - > - <iconify-icon noobserver icon="ph:plus-bold" width="28"></iconify-icon> - </button> - </a> - </div> + <a href="/account/new" class="contents"> + <button class="btn btn-accent w-full"> + <iconify-icon noobserver icon="ph:plus-bold" width="24"></iconify-icon> + {$t("accounts.addAccount")} + </button> + </a> </div> {#if locked} diff --git a/src/routes/(app)/account/[id]/+page.svelte b/src/routes/(app)/account/[id]/+page.svelte index fa9d744d..157dd096 100644 --- a/src/routes/(app)/account/[id]/+page.svelte +++ b/src/routes/(app)/account/[id]/+page.svelte @@ -30,7 +30,7 @@ let currency = $state(data.account.currency || data.user.currency); let autowithdraw = $state(data.account.autowithdraw || false); let threshold = $state(data.account.threshold || data.user.threshold || 1000000); - let reserve = $state(data.account.reserve || data.user.reserve || 0); + let reserve = $state(data.account.reserve ?? 0); let destination = $state(data.account.destination || data.user.destination || ""); let rate = $derived(rates[currency]); @@ -113,21 +113,19 @@ </script> <div class="space-y-5"> - <h1 class="text-center text-3xl font-semibold">{$t("payments.accountSettings")}</h1> + <h1 class="text-center text-3xl font-semibold flex items-center justify-center gap-2"> + {#if account.type === "ark"} + <img src="/images/ark.png" class="w-8 h-8 rounded-full object-cover" alt="Ark" /> + {:else if seed} + <iconify-icon noobserver icon="cryptocurrency-color:btc" width="32"></iconify-icon> + {:else} + <img src="/images/icon.png" class="w-8 h-8" alt="Coinos" /> + {/if} + {displayType} {$t("payments.accountSettings").toLowerCase()} + </h1> <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-2"> <form class="space-y-5 pb-8" method="POST" use:enhance> - <div class="flex items-center gap-2 text-lg"> - <span class="font-bold">{$t("accounts.accountType")}:</span> - {#if account.type === "ark"} - <img src="/images/ark.png" class="w-6 h-6 rounded-full object-cover" alt="Ark" /> - {:else if seed} - <iconify-icon noobserver icon="cryptocurrency-color:btc" width="24"></iconify-icon> - {:else} - <img src="/images/icon.png" class="w-6 h-6" alt="Coinos" /> - {/if} - {displayType} - </div> <div class="space-y-1"> <label for="name" class="font-bold block">{$t("accounts.name")}</label> @@ -213,7 +211,7 @@ </button> {/if} - {#if seed} + {#if seed || account.type === "ark"} <button onclick={del} type="button" class="btn"> <iconify-icon noobserver icon="ph:trash-bold" width="32"></iconify-icon> <div class="my-auto">{$t("accounts.deleteAccount")}</div> diff --git a/src/routes/(app)/invoice/[id]/+page.svelte b/src/routes/(app)/invoice/[id]/+page.svelte index d8f30fd1..e4a5b85e 100644 --- a/src/routes/(app)/invoice/[id]/+page.svelte +++ b/src/routes/(app)/invoice/[id]/+page.svelte @@ -94,7 +94,7 @@ invoice.address_type = address_type; invoice.type = type; - if (type === "ark") { + if (type === "ark" && invoice.aid !== invoice.uid) { const wallet = await getWallet(); invoice.hash = await wallet.getAddress(); } |
