diff options
| author | Adam Soltys <[email protected]> | 2026-02-14 15:46:01 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-14 15:46:01 -0800 |
| commit | 526b21bc668c453250ebce8dece9ba330bac0133 (patch) | |
| tree | 5e9c84a2cca6b4a5766c6cdc9f33f6c62f5776f3 /lib | |
| parent | 843c343db567cd224dadf347ac16736bdc8b24a8 (diff) | |
| download | coinos-server-526b21bc668c453250ebce8dece9ba330bac0133.tar.gz coinos-server-526b21bc668c453250ebce8dece9ba330bac0133.zip | |
custodial ark sends
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/ark.ts | 14 | ||||
| -rw-r--r-- | lib/db.ts | 8 | ||||
| -rw-r--r-- | lib/invoices.ts | 18 | ||||
| -rw-r--r-- | lib/lightning.ts | 4 | ||||
| -rw-r--r-- | lib/migrate.ts | 12 | ||||
| -rw-r--r-- | lib/payments.ts | 22 |
6 files changed, 50 insertions, 28 deletions
@@ -9,16 +9,22 @@ let wallet: any; const getWallet = async () => { if (wallet) return wallet; - const { arkPrivateKey, arkServerUrl } = config.ark; + const { arkPrivateKey, arkServerUrl, esploraUrl } = config.ark; const identity = SingleKey.fromHex(arkPrivateKey); - wallet = await Wallet.create({ identity, arkServerUrl }); + wallet = await Wallet.create({ identity, arkServerUrl, esploraUrl }); return wallet; }; export const sendArk = async (address: string, amount: number) => { - const w = await getWallet(); - return w.sendBitcoin({ address, amount }); + const timeout = new Promise((_, reject) => + setTimeout(() => reject(new Error("Ark send timed out")), 45000), + ); + const send = async () => { + const w = await getWallet(); + return w.sendBitcoin({ address, amount }); + }; + return Promise.race([send(), timeout]); }; export const getArkAddress = async () => { @@ -67,9 +67,15 @@ export const g = async (k) => { export const s = (k, v) => { if (k === "user:null" || k === "user:undefined") fail("null user"); - db.set(k, JSON.stringify(v)); + return db.set(k, JSON.stringify(v)); }; +export async function* scan(pattern: string) { + for await (const keys of db.scanIterator({ MATCH: pattern })) { + for (const k of keys) yield k; + } +} + export const ga = async (k) => { const v = await archive.get(k); try { diff --git a/lib/invoices.ts b/lib/invoices.ts index bf6c511e..f7bb6897 100644 --- a/lib/invoices.ts +++ b/lib/invoices.ts @@ -69,9 +69,25 @@ export const generate = async ({ invoice, user }) => { let path; let paymentHash; - if (account.type === "ark") { + if (type === PaymentType.ark && account.type !== "ark") { + // Custodial account receiving via Ark: use vault's ark address + const accounts = await db.lRange(`${user.id}:accounts`, 0, -1); + let vaultAddress; + for (const accId of accounts) { + const acc = await g(`account:${accId}`); + if (acc?.type === "ark" && acc.arkAddress) { + vaultAddress = acc.arkAddress; + break; + } + } + if (!vaultAddress) fail("No ark vault found"); + text = vaultAddress; + hash = id; + await s(`custodial-ark-invoice:${vaultAddress}`, id); + } else if (account.type === "ark") { type = PaymentType.ark; text = account.arkAddress; + hash = id; } else if (account.seed || (account.pubkey && account.fingerprint)) { type = PaymentType.bitcoin; const nextIndex = account.nextIndex || 0; diff --git a/lib/lightning.ts b/lib/lightning.ts index e4c2e3cb..4824d9ab 100644 --- a/lib/lightning.ts +++ b/lib/lightning.ts @@ -1,4 +1,4 @@ -import { db, g, s } from "$lib/db"; +import { db, g, s, scan } from "$lib/db"; import ln, { lnListen, LightningUnavailableError } from "$lib/ln"; import { err, l, warn } from "$lib/logging"; import { handleZap } from "$lib/nostr"; @@ -171,7 +171,7 @@ export async function replay(index) { } export const fixBolt12 = async (_, res) => { - for await (const k of db.scanIterator({ MATCH: "payment:*" })) { + for await (const k of scan("payment:*")) { const p = await g(k); if (p.type === "bolt12") { console.log(k); diff --git a/lib/migrate.ts b/lib/migrate.ts index d0e38276..79f9546c 100644 --- a/lib/migrate.ts +++ b/lib/migrate.ts @@ -1,4 +1,4 @@ -import { db, g, s } from "$lib/db"; +import { db, g, s, scan } from "$lib/db"; import { findLastUsedIndex, parseDescriptor } from "$lib/esplora"; import { l, warn } from "$lib/logging"; import { @@ -64,7 +64,7 @@ export const migrateBalancesToTB = async () => { let count = 0; // Migrate balance:* keys - for await (const k of db.scanIterator({ MATCH: "balance:*" })) { + for await (const k of scan("balance:*")) { try { const id = k.split(":")[1]; const balance = Number.parseInt((await db.get(k)) || "0"); @@ -77,7 +77,7 @@ export const migrateBalancesToTB = async () => { } // Migrate pending:* keys - for await (const k of db.scanIterator({ MATCH: "pending:*" })) { + for await (const k of scan("pending:*")) { try { const id = k.split(":")[1]; const pending = Number.parseInt((await db.get(k)) || "0"); @@ -88,7 +88,7 @@ export const migrateBalancesToTB = async () => { } // Migrate credit:*:* keys - for await (const k of db.scanIterator({ MATCH: "credit:*:*" })) { + for await (const k of scan("credit:*:*")) { try { const parts = k.split(":"); const type = parts[1]; @@ -113,7 +113,7 @@ export const migrateToMicrosats = async () => { let count = 0; // Iterate through all users and multiply their TB balances - for await (const k of db.scanIterator({ MATCH: "user:*" })) { + for await (const k of scan("user:*")) { try { const raw = await db.get(k); if (!raw) continue; @@ -142,7 +142,7 @@ export const migrateAutowithdraw = async () => { let count = 0; - for await (const k of db.scanIterator({ MATCH: "user:*" })) { + for await (const k of scan("user:*")) { try { const raw = await db.get(k); if (!raw || !raw.startsWith("{")) continue; diff --git a/lib/payments.ts b/lib/payments.ts index f6a6bd23..03b52dfa 100644 --- a/lib/payments.ts +++ b/lib/payments.ts @@ -520,6 +520,14 @@ const pay = async ({ aid = undefined, amount, to, user }) => { }); if (to.startsWith("ark") || to.startsWith("tark")) { + // Check for local vault - do internal transfer + const vault = await g(`arkaddr:${to}`); + if (vault) { + const recipient = await getUser(vault.uid); + if (recipient) + return sendInternal({ amount, recipient, sender: user }); + } + const txid = await sendArk(to, amount); const p = await debit({ hash: txid, @@ -528,20 +536,6 @@ const pay = async ({ aid = undefined, amount, to, user }) => { type: PaymentType.ark, }); - const vault = await g(`arkaddr:${to}`); - if (vault) { - const { rate, currency } = await getUserRate(user); - await createArkPayment({ - aid: vault.aid, - uid: vault.uid, - amount, - hash: txid, - rate, - currency, - extraHashMappings: [txid], - }); - } - return p; } |
