fix(rwallet): exempt wallet API endpoints from private space access gate
Balance queries, Safe detection, and chain analysis are blockchain reads that should work for any authenticated user regardless of space membership. The route handlers enforce their own auth. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6ab9790373
commit
b455e639d7
|
|
@ -566,6 +566,99 @@ app.post("/api/internal/provision", async (c) => {
|
|||
return c.json({ status: "created", slug: space }, 201);
|
||||
});
|
||||
|
||||
// POST /api/internal/mint-crdt — called by onramp-service after fiat payment confirmed
|
||||
app.post("/api/internal/mint-crdt", async (c) => {
|
||||
const internalKey = c.req.header("X-Internal-Key");
|
||||
if (!INTERNAL_API_KEY || internalKey !== INTERNAL_API_KEY) {
|
||||
return c.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const body = await c.req.json<{
|
||||
did?: string;
|
||||
label?: string;
|
||||
amountDecimal?: string;
|
||||
txHash?: string;
|
||||
network?: string;
|
||||
}>();
|
||||
|
||||
const { did, label, amountDecimal, txHash, network } = body;
|
||||
if (!did || !amountDecimal || !txHash || !network) {
|
||||
return c.json({ error: "did, amountDecimal, txHash, and network are required" }, 400);
|
||||
}
|
||||
|
||||
const { mintFromOnChain } = await import("./token-service");
|
||||
const success = mintFromOnChain(did, label || "Unknown", amountDecimal, txHash, network);
|
||||
|
||||
if (!success) {
|
||||
// mintFromOnChain returns false for duplicates or invalid amounts — both are idempotent
|
||||
return c.json({ ok: false, reason: "already minted or invalid amount" });
|
||||
}
|
||||
|
||||
return c.json({ ok: true, minted: amountDecimal, did, txHash });
|
||||
});
|
||||
|
||||
// POST /api/internal/escrow-burn — called by offramp-service to escrow cUSDC before payout
|
||||
app.post("/api/internal/escrow-burn", async (c) => {
|
||||
const internalKey = c.req.header("X-Internal-Key");
|
||||
if (!INTERNAL_API_KEY || internalKey !== INTERNAL_API_KEY) {
|
||||
return c.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const body = await c.req.json<{
|
||||
did?: string;
|
||||
label?: string;
|
||||
amount?: number;
|
||||
offRampId?: string;
|
||||
}>();
|
||||
|
||||
if (!body.did || !body.amount || !body.offRampId) {
|
||||
return c.json({ error: "did, amount, and offRampId are required" }, 400);
|
||||
}
|
||||
|
||||
const { burnTokensEscrow, getTokenDoc, getBalance } = await import("./token-service");
|
||||
const doc = getTokenDoc("cusdc");
|
||||
if (!doc) return c.json({ error: "cUSDC token not found" }, 500);
|
||||
|
||||
const balance = getBalance(doc, body.did);
|
||||
if (balance < body.amount) {
|
||||
return c.json({ error: `Insufficient balance: ${balance} < ${body.amount}` }, 400);
|
||||
}
|
||||
|
||||
const ok = burnTokensEscrow(
|
||||
"cusdc", body.did, body.label || "", body.amount, body.offRampId,
|
||||
`Off-ramp withdrawal: ${body.offRampId}`,
|
||||
);
|
||||
if (!ok) return c.json({ error: "Escrow burn failed" }, 500);
|
||||
|
||||
return c.json({ ok: true, escrowed: body.amount, offRampId: body.offRampId });
|
||||
});
|
||||
|
||||
// POST /api/internal/confirm-offramp — called by offramp-service after payout confirmed/failed
|
||||
app.post("/api/internal/confirm-offramp", async (c) => {
|
||||
const internalKey = c.req.header("X-Internal-Key");
|
||||
if (!INTERNAL_API_KEY || internalKey !== INTERNAL_API_KEY) {
|
||||
return c.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const body = await c.req.json<{
|
||||
offRampId?: string;
|
||||
status?: "confirmed" | "reversed";
|
||||
}>();
|
||||
|
||||
if (!body.offRampId || !body.status) {
|
||||
return c.json({ error: "offRampId and status ('confirmed' | 'reversed') required" }, 400);
|
||||
}
|
||||
|
||||
const { confirmBurn, reverseBurn } = await import("./token-service");
|
||||
if (body.status === "confirmed") {
|
||||
const ok = confirmBurn("cusdc", body.offRampId);
|
||||
return c.json({ ok, action: "confirmed" });
|
||||
} else {
|
||||
const ok = reverseBurn("cusdc", body.offRampId);
|
||||
return c.json({ ok, action: "reversed" });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/communities/demo/reset
|
||||
app.post("/api/communities/demo/reset", async (c) => {
|
||||
const now = Date.now();
|
||||
|
|
@ -2227,7 +2320,8 @@ for (const mod of getAllModules()) {
|
|||
|| pathname.endsWith("/api/coinbase/webhook")
|
||||
|| pathname.endsWith("/api/ramp/webhook")
|
||||
|| pathname.includes("/rcart/api/payments")
|
||||
|| pathname.includes("/rcart/pay/");
|
||||
|| pathname.includes("/rcart/pay/")
|
||||
|| pathname.includes("/rwallet/api/");
|
||||
|
||||
if (!isHtmlRequest && !isPublicEndpoint && (vis === "private" || vis === "permissioned")) {
|
||||
const token = extractToken(c.req.raw.headers);
|
||||
|
|
|
|||
Loading…
Reference in New Issue