aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-21 19:32:54 -0700
committerAdam Soltys <[email protected]>2026-09-21 19:32:54 -0700
commitd128ee51c292c331ea1f26d745a5fc280fb3f439 (patch)
tree408aea3bdbf9eeecab74f238faa70c89259f5d64 /routes
parent38f3baf94d08b0e3ec40e6bacc4e330459e2a4d3 (diff)
downloadcoinos-server-d128ee51c292c331ea1f26d745a5fc280fb3f439.tar.gz
coinos-server-d128ee51c292c331ea1f26d745a5fc280fb3f439.zip
funds: close deposits, withdrawals and authorizations
The fund mechanism is retired. Deposits (POST /payments with `fund`), withdrawals (POST /take) and pre-authorizations (POST /authorize) now refuse unconditionally instead of consulting the `fund:disabled` flag, so the door cannot be reopened by clearing a key. The deposit path never had a kill-switch of its own, so with the flag set users could still pay into funds they were unable to withdraw from. Read paths are left intact: GET /fund/:id and the manager endpoints still serve existing funds so balances stay visible and can be settled out of band. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Diffstat (limited to 'routes')
-rw-r--r--routes/payments.ts33
1 files changed, 16 insertions, 17 deletions
diff --git a/routes/payments.ts b/routes/payments.ts
index 78c0660b..5fc927b2 100644
--- a/routes/payments.ts
+++ b/routes/payments.ts
@@ -34,6 +34,19 @@ import rpc from "@coinos/rpc";
import got from "got";
import { v4 } from "uuid";
+// Funds are closed. The mechanism let a caller pull unbacked balance out of a
+// fund (the /take drain, 2026-08-25) and its deposit path never had a
+// kill-switch of its own, so with `fund:disabled` set users could still pay
+// INTO funds they were then unable to withdraw from. Every value-moving entry
+// point — deposit (POST /payments with `fund`), withdrawal (POST /take) and
+// pre-authorization (POST /authorize) — now refuses unconditionally, rather
+// than depending on a redis flag someone can clear by accident.
+//
+// Read paths are deliberately left working: GET /fund/:id and the manager
+// endpoints still serve existing funds so balances stay visible and can be
+// settled out of band.
+const fundsClosed = () => fail("Funds are no longer supported");
+
export default {
async info(_, res) {
res.send(await ln.getinfo());
@@ -86,16 +99,7 @@ export default {
sender: user,
});
} else if (fund) {
- p = await debit({
- hash,
- amount,
- memo: fund,
- user,
- type: PaymentType.fund,
- });
- await db.incrBy(`fund:${fund}`, amount);
- await db.lPush(`fund:${fund}:payments`, p.id);
- l("funded fund", fund);
+ fundsClosed();
}
}
@@ -322,11 +326,7 @@ export default {
// },
async authorize(req, res) {
- // Kill-switch for the fund/authorize/take mechanism (SECURITY 2026-08-25:
- // the /take fund-claim path could pay out unbacked balance). Set redis
- // `fund:disabled` to fail all
- // fund authorizations closed while the mechanism is audited/rewritten.
- if (await g("fund:disabled")) fail("Fund transfers temporarily disabled");
+ fundsClosed();
const { id: uid } = req.user;
const { id, fiat, currency, amount } = req.body;
@@ -361,8 +361,7 @@ export default {
user,
} = req;
try {
- // Kill-switch — see authorize().
- if (await g("fund:disabled")) fail("Fund transfers temporarily disabled");
+ fundsClosed();
amount = Number.parseInt(amount);
if (!Number.isFinite(amount) || amount <= 0) fail("Invalid amount");