aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-03-22 15:41:08 +0000
committerAdam Soltys <[email protected]>2026-03-22 15:41:12 +0000
commitaf568c46cb3da198ea8614d21616bac3951f3262 (patch)
treeccf52aceb6dc7ae85555c19730dc9dcf0f8df34c
parent5df889030899915c4c99e776464a49978ee8b0db (diff)
downloadcoinos-server-af568c46cb3da198ea8614d21616bac3951f3262.tar.gz
coinos-server-af568c46cb3da198ea8614d21616bac3951f3262.zip
verify ark amounts
-rw-r--r--lib/ark.ts5
-rw-r--r--lib/payments.ts2
-rw-r--r--loki-config.yml42
-rw-r--r--promtail-config.yml19
-rw-r--r--routes/payments.ts47
5 files changed, 94 insertions, 21 deletions
diff --git a/lib/ark.ts b/lib/ark.ts
index 3c2a3087..a37197e8 100644
--- a/lib/ark.ts
+++ b/lib/ark.ts
@@ -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) {