diff options
| author | Adam Soltys <[email protected]> | 2026-02-11 10:45:39 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-11 15:34:39 -0800 |
| commit | e8e3fe413f02b9520bd3539f351c344134148c58 (patch) | |
| tree | bf2508e6228c060ffc6df6efc09a39e1a3732234 /src | |
| parent | 2cc4969678f4d073ebddec0e7e9f2aac707fb761 (diff) | |
| download | coinos-ui-e8e3fe413f02b9520bd3539f351c344134148c58.tar.gz coinos-ui-e8e3fe413f02b9520bd3539f351c344134148c58.zip | |
ark payment test
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Account.svelte | 4 | ||||
| -rw-r--r-- | src/components/InvoiceData.svelte | 1 | ||||
| -rw-r--r-- | src/components/WalletPass.svelte | 4 | ||||
| -rw-r--r-- | src/routes/test/ark/send/+server.ts | 76 |
4 files changed, 84 insertions, 1 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte index 711c5ba7..bb9aec22 100644 --- a/src/components/Account.svelte +++ b/src/components/Account.svelte @@ -142,6 +142,8 @@ <div class="shadow-lg space-y-4 p-4 cursor-pointer hover:bg-base-200" aria-label="Payments" + data-testid="account-card" + data-account-type={accountType} role="button" tabindex="0" onclick={goPayments} @@ -180,7 +182,7 @@ class="contents" onclick={(e) => setAccount(e, "/invoice")} > - <button class="btn !w-auto flex-1 !bg-base-300"> + <button class="btn !w-auto flex-1 !bg-base-300" data-testid="account-receive"> <iconify-icon noobserver icon="ph:hand-coins-bold" diff --git a/src/components/InvoiceData.svelte b/src/components/InvoiceData.svelte index e0ec0f3e..5ba950d5 100644 --- a/src/components/InvoiceData.svelte +++ b/src/components/InvoiceData.svelte @@ -56,6 +56,7 @@ {#if !showQr || txt?.length <= 120} <div + data-testid="invoice-text" class="break-all text-center text-secondary text-xl flex gap-1 items-center justify-center" > {txt} diff --git a/src/components/WalletPass.svelte b/src/components/WalletPass.svelte index e0dcf961..11f6978a 100644 --- a/src/components/WalletPass.svelte +++ b/src/components/WalletPass.svelte @@ -37,6 +37,7 @@ {#if revealPassword} <input name="password" + data-testid="walletpass-input" type="text" required bind:value={password} @@ -46,6 +47,7 @@ {:else} <input name="password" + data-testid="walletpass-input" type="password" required bind:value={password} @@ -83,6 +85,7 @@ <div class="w-full flex justify-center gap-2"> <button type="button" + data-testid="walletpass-cancel" class="border rounded-2xl font-semibold mx-auto py-5 px-6 hover:opacity-80 mx-auto grow" onclick={cancel} onkeydown={cancel} @@ -91,6 +94,7 @@ </button> <button type="submit" + data-testid="walletpass-submit" class="border rounded-2xl font-semibold mx-auto py-5 px-6 hover:opacity-80 mx-auto grow" > <div class="my-auto">Submit</div> diff --git a/src/routes/test/ark/send/+server.ts b/src/routes/test/ark/send/+server.ts new file mode 100644 index 00000000..b077c793 --- /dev/null +++ b/src/routes/test/ark/send/+server.ts @@ -0,0 +1,76 @@ +import { env } from "$env/dynamic/private"; +import { PUBLIC_COINOS_URL } from "$env/static/public"; +import { error, json } from "@sveltejs/kit"; + +let walletPromise: Promise<any> | undefined; + +const getWallet = async () => { + if (!walletPromise) { + const privateKey = env.ARK_SERVER_WALLET_PRIVATE_KEY; + const arkServerUrl = env.ARK_SERVER_URL || "http://localhost:7070"; + + if (!privateKey) { + throw new Error("ARK_SERVER_WALLET_PRIVATE_KEY is not configured"); + } + + const { SingleKey, Wallet } = await import("@arkade-os/sdk"); + const identity = SingleKey.fromHex(privateKey); + walletPromise = Wallet.create({ identity, arkServerUrl }); + } + + return walletPromise; +}; + +export async function POST({ request, cookies, fetch }) { + // Never expose this in production. + if (env.NODE_ENV === "production") error(404, "Not found"); + + // Require explicit opt-in for local/integration test environments. + if (env.ENABLE_E2E_TEST_ENDPOINTS !== "true") { + error(404, "Not found"); + } + + const expectedSecret = env.E2E_TEST_SECRET; + const providedSecret = request.headers.get("x-test-secret"); + if (!expectedSecret || providedSecret !== expectedSecret) { + error(401, "Unauthorized"); + } + + const body = await request.json(); + const address = String(body?.address || "").trim(); + const amount = Number(body?.amount || 1000); + const iid = typeof body?.iid === "string" ? body.iid : undefined; + + if (!/^t?ark1[a-z0-9]+$/i.test(address)) { + error(400, "Invalid ark address"); + } + + if (!Number.isInteger(amount) || amount <= 0 || amount > 1_000_000) { + error(400, "Invalid amount"); + } + + const wallet = await getWallet(); + const txid = await wallet.sendBitcoin({ address, amount }); + + // Optional: mark an Ark invoice as received right after send. + if (iid) { + const token = cookies.get("token"); + if (!token) error(401, "Missing auth token cookie"); + + const response = await fetch(`${PUBLIC_COINOS_URL}/ark/receive`, { + method: "POST", + headers: { + "content-type": "application/json", + accept: "application/json", + authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ iid, amount, hash: txid }), + }); + + if (!response.ok) { + error(response.status, await response.text()); + } + } + + return json({ ok: true, txid, amount, address, iid: iid || null }); +} |
