diff options
| author | Adam Soltys <[email protected]> | 2026-03-22 15:41:08 +0000 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-22 15:41:12 +0000 |
| commit | af568c46cb3da198ea8614d21616bac3951f3262 (patch) | |
| tree | ccf52aceb6dc7ae85555c19730dc9dcf0f8df34c | |
| parent | 5df889030899915c4c99e776464a49978ee8b0db (diff) | |
| download | coinos-server-af568c46cb3da198ea8614d21616bac3951f3262.tar.gz coinos-server-af568c46cb3da198ea8614d21616bac3951f3262.zip | |
verify ark amounts
| -rw-r--r-- | lib/ark.ts | 5 | ||||
| -rw-r--r-- | lib/payments.ts | 2 | ||||
| -rw-r--r-- | loki-config.yml | 42 | ||||
| -rw-r--r-- | promtail-config.yml | 19 | ||||
| -rw-r--r-- | routes/payments.ts | 47 |
5 files changed, 94 insertions, 21 deletions
@@ -230,7 +230,7 @@ let cachedArkBalance: any = null; export const getArkBalance = () => cachedArkBalance; -export const verifyArkVtxo = async (hash: string) => { +export const verifyArkVtxo = async (hash: string): Promise<{ found: boolean; amount: number }> => { const { bech32m } = await import("@scure/base"); const serverAddr = await getArkAddress(); const decoded = bech32m.decode(serverAddr, 1023); @@ -240,5 +240,6 @@ export const verifyArkVtxo = async (hash: string) => { `${config.ark.arkServerUrl}/v1/indexer/vtxos?scripts=5120${vtxoHex}&spendable_only=true`, ); const { vtxos } = await r.json() as any; - return vtxos?.some((v: any) => v.outpoint?.txid === hash) ?? false; + const vtxo = vtxos?.find((v: any) => v.outpoint?.txid === hash); + return { found: !!vtxo, amount: vtxo?.amount ?? 0 }; }; diff --git a/lib/payments.ts b/lib/payments.ts index 78f20684..b82ea767 100644 --- a/lib/payments.ts +++ b/lib/payments.ts @@ -88,7 +88,7 @@ export const getUserRate = async (user) => { }; export const acquireArkLock = async (hash) => { - const locked = await db.set(`arklock:${hash}`, "1", { NX: true, EX: 60 }); + const locked = await db.set(`arklock:${hash}`, "1", { NX: true }); if (!locked) fail("Already processed"); }; diff --git a/loki-config.yml b/loki-config.yml new file mode 100644 index 00000000..d43e2ed7 --- /dev/null +++ b/loki-config.yml @@ -0,0 +1,42 @@ +auth_enabled: false + +server: + http_listen_port: 3100 + +common: + path_prefix: /loki + storage: + filesystem: + chunks_directory: /loki/chunks + rules_directory: /loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +schema_config: + configs: + - from: 2020-10-24 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + +limits_config: + retention_period: 30d + ingestion_rate_mb: 32 + ingestion_burst_size_mb: 64 + +compactor: + working_directory: /loki/compactor + retention_enabled: true + delete_request_store: filesystem + +query_range: + results_cache: + cache: + embedded_cache: + enabled: true + max_size_mb: 100 diff --git a/promtail-config.yml b/promtail-config.yml new file mode 100644 index 00000000..5d7f5e4a --- /dev/null +++ b/promtail-config.yml @@ -0,0 +1,19 @@ +server: + http_listen_port: 9080 + +positions: + filename: /tmp/positions.yaml + +clients: + - url: http://loki:3100/loki/api/v1/push + +scrape_configs: + - job_name: docker + docker_sd_configs: + - host: unix:///var/run/docker.sock + refresh_interval: 5s + relabel_configs: + - source_labels: ["__meta_docker_container_name"] + target_label: container + - source_labels: ["__meta_docker_container_log_stream"] + target_label: stream diff --git a/routes/payments.ts b/routes/payments.ts index 4648716f..56dcad21 100644 --- a/routes/payments.ts +++ b/routes/payments.ts @@ -939,17 +939,23 @@ export default { try { const body = await c.req.json(); const user = c.get("user"); - const { amount, hash, aid } = body; + const hash = body.hash || body.arkTxid; + const { aid } = body; await requireAccountOwnership(db, user.id, aid); - if (amount <= 0) fail("Invalid amount"); + if (!hash) fail("Missing transaction hash"); await acquireArkLock(hash); + + const { found, amount: verifiedAmount } = await verifyArkVtxo(hash); + if (!found) fail("VTXO not found"); + if (verifiedAmount <= 0) fail("Invalid VTXO amount"); + const { rate, currency } = await getUserRate(user); const p = await createArkPayment({ aid, uid: user.id, - amount, + amount: verifiedAmount, hash, rate, currency, @@ -969,34 +975,33 @@ export default { try { const body = await c.req.json(); const user = c.get("user"); - const { iid, amount, hash } = body; + const hash = body.hash || body.arkTxid; + const { iid } = body; const { id: uid } = user; - if (amount <= 0) fail("Invalid amount"); + if (!hash) fail("Missing transaction hash"); const invoice = await getInvoice(iid); if (invoice.uid !== user?.id) fail("Unauthorized"); let { aid, type, currency } = invoice; - if (hash) { - await acquireArkLock(hash); + await acquireArkLock(hash); - if (!(aid && aid !== uid)) { - if (!(await verifyArkVtxo(hash))) fail("VTXO not found in server wallet"); - } - } + const { found, amount: verifiedAmount } = await verifyArkVtxo(hash); + if (!found) fail("VTXO not found in server wallet"); + if (verifiedAmount <= 0) fail("Invalid VTXO amount"); - invoice.received += amount; + invoice.received += verifiedAmount; const { rates } = await getUserRate(user); const rate = rates[currency]; - await tbCredit(uid, uid, type, amount, false); + await tbCredit(uid, uid, type, verifiedAmount, false); const p = await createArkPayment({ aid: uid, uid, - amount, + amount: verifiedAmount, hash, rate, currency, @@ -1004,7 +1009,7 @@ export default { iid, extraMultiOps: (m, p) => { m.set(`invoice:${invoice.id}`, JSON.stringify(invoice)); - if (hash) m.set(`payment:${aid}:${hash}`, p.id); + m.set(`payment:${aid}:${hash}`, p.id); }, }); @@ -1073,10 +1078,16 @@ export default { const primaryHash = hashes[0]; + const locked = await db.set(`arklock:${primaryHash}`, "1", { NX: true }); + if (!locked) continue; + + const { found: vtxoFound, amount: verifiedAmount } = await verifyArkVtxo(primaryHash); + if (!vtxoFound || verifiedAmount <= 0) continue; + const p = await createArkPayment({ aid, uid, - amount: tx.amount, + amount: verifiedAmount, hash: primaryHash, rate, currency, @@ -1086,8 +1097,8 @@ export default { payments.push(p); synced++; - if (tx.amount > 0) { - received += tx.amount; + if (verifiedAmount > 0) { + received += verifiedAmount; const invoiceIds = await db.lRange(`${aid}:invoices`, 0, 20); for (const iid of invoiceIds) { |
