From 91f0517b8d72a2a45c7f6423597808b2e4a6f0aa Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 13 Mar 2026 14:25:51 -0700 Subject: delegation --- src/lib/ark.ts | 34 +++++++++++++++++++++- src/routes/(app)/payment/[id]/+page.svelte | 26 ++++++++++------- .../(app)/send/ark/[address]/+layout.server.ts | 7 ----- .../(app)/send/ark/[address]/+page.server.ts | 7 ----- .../[amount]/[...feeRate]/+page.server.ts | 8 ----- .../[address]/[amount]/[...feeRate]/+page.svelte | 1 + 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/lib/ark.ts b/src/lib/ark.ts index a848e5c7..42ab822a 100644 --- a/src/lib/ark.ts +++ b/src/lib/ark.ts @@ -7,6 +7,8 @@ export const arkServerUrl = { bitcoin: "https://arkade.computer", regtest: "http://localhost:7070", }[PUBLIC_COINOS_NETWORK || "regtest"]; +// Delegator runs on the coinos server, accessed via /api proxy +const delegatorUrl = "/api"; export const arkkey = persistLocal("arkkey", ""); export const arkaid = persistLocal("arkaid", ""); @@ -53,12 +55,14 @@ export const getWallet = async () => { } if (walletInstance && walletKey === key) return walletInstance; - const { SingleKey, Wallet } = await loadArkSdk(); + const { SingleKey, Wallet, RestDelegatorProvider } = await loadArkSdk(); const identity = SingleKey.fromHex(key); + const delegatorProvider = new RestDelegatorProvider(delegatorUrl); walletInstance = await Wallet.create({ identity, arkServerUrl, + delegatorProvider, }); walletKey = key; return walletInstance; @@ -305,6 +309,7 @@ const _syncTransactions = async (aid: string) => { const result = await post("/ark/sync", { transactions, aid, balance, arkAddress: walletAddr }); cacheVaultSnapshot(); // fire-and-forget + delegateVtxos(); // fire-and-forget return result; }; @@ -496,6 +501,8 @@ export const refresh = async () => { const vtxos = await wallet.getVtxos({ spendableOnly: false }); if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); } + + delegateVtxos(); // fire-and-forget }; export const settle = async () => { @@ -511,6 +518,31 @@ export const settle = async () => { // ignores renewed VTXOs (they get new txids after an Ark round) const vtxos = await wallet.getVtxos({ spendableOnly: false }); if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); + + delegateVtxos(); // fire-and-forget +}; + +export const delegateVtxos = async () => { + try { + const wallet = await getWallet(); + if (!wallet) return; + if (!wallet.delegatorManager) return; + + const vtxos = await wallet.getVtxos({ spendableOnly: true }); + if (!vtxos?.length) return; + + const address = await wallet.getAddress(); + const { delegated, failed } = await wallet.delegatorManager.delegate(vtxos, address); + + if (delegated.length > 0) { + console.log("[ark] delegated", delegated.length, "vtxos for renewal"); + } + if (failed.length > 0) { + console.warn("[ark] delegation failed for", failed.length, "groups"); + } + } catch (e: any) { + console.warn("[ark] delegation failed:", e.message); + } }; // Service Worker wallet for background fund notifications diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte index 03023e8a..3b41cc4f 100644 --- a/src/routes/(app)/payment/[id]/+page.svelte +++ b/src/routes/(app)/payment/[id]/+page.svelte @@ -249,17 +249,6 @@ {@render copyable("Child Txid", p.childTxid, `${expl}/tx/${p.childTxid}`)} {/if} - {#if canBump} -
- - {#if bumpError} -
{bumpError}
- {/if} -
- {/if} - {#if type === types.lightning || type === types.bolt12} {@render copyable($t("payments.invoice"), hash)} {@render copyable($t("payments.preimage"), ref)} @@ -277,8 +266,23 @@ {@render copyable("Address", hash, `${expl}/address/${hash}`)} {/if} + {#if (type === "bitcoin" || type === "liquid") && amount < 0 && p.address} + {@render copyable("Address", p.address, `${expl}/address/${p.address}`)} + {/if} + {#if path} {@render copyable("Path", path)} {/if} + + {#if canBump} +
+ + {#if bumpError} +
{bumpError}
+ {/if} +
+ {/if} diff --git a/src/routes/(app)/send/ark/[address]/+layout.server.ts b/src/routes/(app)/send/ark/[address]/+layout.server.ts index 18fb7aed..b17d89bc 100644 --- a/src/routes/(app)/send/ark/[address]/+layout.server.ts +++ b/src/routes/(app)/send/ark/[address]/+layout.server.ts @@ -7,13 +7,6 @@ export async function load({ cookies, params, parent, url }) { const { address, amount } = params; let account = await get(`/account/${aid}`, auth(cookies)); - // Fall back to custodial if cookie points to ark account - if (account.type === "ark" && aid !== user.id) { - aid = user.id; - account = await get(`/account/${aid}`, auth(cookies)); - cookies.set("aid", aid, { path: "/", maxAge: 86400, httpOnly: false }); - } - let invoice; try { invoice = await get(`/invoice/${address}`); diff --git a/src/routes/(app)/send/ark/[address]/+page.server.ts b/src/routes/(app)/send/ark/[address]/+page.server.ts index 83a5050f..086e6daa 100644 --- a/src/routes/(app)/send/ark/[address]/+page.server.ts +++ b/src/routes/(app)/send/ark/[address]/+page.server.ts @@ -7,12 +7,5 @@ export async function load({ cookies, parent, url }) { let aid = url.searchParams.get("aid") || cookies.get("aid") || user.id; let account = await get(`/account/${aid}`, auth(cookies)); - // Fall back to custodial if cookie points to ark account - if (account.type === "ark" && aid !== user.id) { - aid = user.id; - account = await get(`/account/${aid}`, auth(cookies)); - cookies.set("aid", aid, { path: "/", maxAge: 86400, httpOnly: false }); - } - return { balance: account.balance, rate: rates[user.currency] }; } diff --git a/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts b/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts index ee0775d3..37a0f068 100644 --- a/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts +++ b/src/routes/(app)/send/ark/[address]/[amount]/[...feeRate]/+page.server.ts @@ -9,14 +9,6 @@ export async function load({ params: { address, amount }, cookies, parent, url } let account = await get(`/account/${aid}`, auth(cookies)); - // If cookie points to an ark account but user is sending TO an ark address, - // fall back to custodial account — ark-to-ark sends use client-side wallet - if (account.type === "ark" && aid !== user.id) { - aid = user.id; - account = await get(`/account/${aid}`, auth(cookies)); - cookies.set("aid", aid, { path: "/", maxAge: 86400, httpOnly: false }); - } - if (account.type === "bitcoin") { const inv = await post( "/invoice", diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte index 86bad61c..7b2c9ccf 100644 --- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte +++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte @@ -281,6 +281,7 @@
+ -- cgit v1.2.3