aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-02-26 11:59:58 -0800
committerAdam Soltys <[email protected]>2025-02-26 11:59:58 -0800
commit1d541fd97210389f006e65d46ab783afbe82cea8 (patch)
tree66781ea2992fa99198ed1e450cdb9b68acfbc4d9
parenta14b987a392bc700975b048f37838da08e4ed255 (diff)
downloadcoinos-server-1d541fd97210389f006e65d46ab783afbe82cea8.tar.gz
coinos-server-1d541fd97210389f006e65d46ab783afbe82cea8.zip
payment types
-rw-r--r--lib/invoices.ts17
-rw-r--r--lib/lightning.ts7
-rw-r--r--lib/migrate.ts132
-rw-r--r--lib/payments.ts69
-rw-r--r--lib/types.ts78
-rw-r--r--lib/utils.ts33
-rw-r--r--routes/ecash.ts8
-rw-r--r--routes/lnurl.ts15
-rw-r--r--routes/payments.ts13
-rw-r--r--routes/users.ts16
-rw-r--r--tsconfig.json1
11 files changed, 168 insertions, 221 deletions
diff --git a/lib/invoices.ts b/lib/invoices.ts
index 4710beb2..178f793a 100644
--- a/lib/invoices.ts
+++ b/lib/invoices.ts
@@ -2,12 +2,13 @@ import config from "$config";
import { db, g, s } from "$lib/db";
import { request } from "$lib/ecash";
import ln from "$lib/ln";
-import { types } from "$lib/payments";
import { emit } from "$lib/sockets";
import { SATS, bip21, fail, getUser } from "$lib/utils";
import rpc from "@coinos/rpc";
import { v4 } from "uuid";
+import { PaymentType } from "$lib/types";
+
const bc = rpc(config.bitcoin);
const lq = rpc(config.liquid);
@@ -27,7 +28,7 @@ export const generate = async ({ invoice, user }) => {
memo,
memoPrompt,
prompt,
- type = types.lightning,
+ type = PaymentType.lightning,
webhook,
secret,
} = invoice;
@@ -65,7 +66,7 @@ export const generate = async ({ invoice, user }) => {
text = bip21(hash, invoice);
({ hdkeypath: path } = await node.getAddressInfo(hash));
- } else if (type === types.lightning) {
+ } else if (type === PaymentType.lightning) {
let r;
if (bolt11) {
const { id: nodeid } = await ln.getinfo();
@@ -87,7 +88,7 @@ export const generate = async ({ invoice, user }) => {
hash = r.bolt11;
text = r.bolt11;
- } else if (type === types.bolt12) {
+ } else if (type === PaymentType.bolt12) {
const r = await ln.offer({
amount: amount ? `${amount + tip}sat` : "any",
label: id,
@@ -100,17 +101,17 @@ export const generate = async ({ invoice, user }) => {
text = r.bolt12;
await s(`invoice:${r.offer_id}`, id);
- } else if (type === types.bitcoin) {
+ } else if (type === PaymentType.bitcoin) {
address_type ||= "bech32";
hash = await bc.getNewAddress({ address_type });
text = bip21(hash, invoice);
- } else if (type === types.liquid) {
+ } else if (type === PaymentType.liquid) {
address_type ||= "blech32";
hash = await lq.getNewAddress({ address_type });
text = bip21(hash, invoice);
- } else if (type === types.internal) {
+ } else if (type === PaymentType.internal) {
hash = id;
- } else if (type === types.ecash) {
+ } else if (type === PaymentType.ecash) {
hash = id;
text = request(id, amount, memo);
} else {
diff --git a/lib/lightning.ts b/lib/lightning.ts
index f63b57be..4d41d9eb 100644
--- a/lib/lightning.ts
+++ b/lib/lightning.ts
@@ -2,8 +2,9 @@ import { db, g, s } from "$lib/db";
import ln from "$lib/ln";
import { err, warn } from "$lib/logging";
import { handleZap } from "$lib/nostr";
-import { credit, types } from "$lib/payments";
+import { credit } from "$lib/payments";
import { getPayment, getUser } from "$lib/utils";
+import { PaymentType } from "$lib/types";
export async function listenForLightning() {
const inv = await ln.waitanyinvoice((await g("pay_index")) || 0);
@@ -49,7 +50,7 @@ export async function listenForLightning() {
amount: received,
memo: invoice.memo,
ref: preimage,
- type: bolt12 ? types.bolt12 : types.lightning,
+ type: bolt12 ? PaymentType.bolt12 : PaymentType.lightning,
});
} catch (e) {
console.log(e);
@@ -97,7 +98,7 @@ export async function replay(index) {
amount: received,
memo: invoice.memo,
ref: preimage,
- type: bolt12 ? types.bolt12 : types.lightning,
+ type: bolt12 ? PaymentType.bolt12 : PaymentType.lightning,
});
} catch (e) {
console.log(e);
diff --git a/lib/migrate.ts b/lib/migrate.ts
index 8da68cd2..58623ec1 100644
--- a/lib/migrate.ts
+++ b/lib/migrate.ts
@@ -1,132 +1,10 @@
-import { archive, db, g, ga, s } from "$lib/db";
-import { err, l, line, warn } from "$lib/logging";
-import { types } from "$lib/payments";
-
-const queued = {};
-const migrating = {};
+import { g } from "$lib/db";
async function migrate(id) {
- try {
- delete queued[id];
- if (id) id = id.replace(/\s/g, "").toLowerCase();
-
- let user = await g(`user:${id}`);
- if (typeof user === "string") user = await g(`user:${user}`);
- return user;
-
- user = await ga(`user:${id}`);
-
- if (typeof user === "string") {
- if (await g(`user:${user}`)) {
- warn("user already migrated", id);
- s(`user:${id}`, user);
- }
-
- id = user;
- user = await ga(`user:${id}`);
- }
-
- if (user) {
- if (migrating[id]) return;
- migrating[id] = true;
-
- let { username } = user;
- username = username.replace(/\s/g, "").toLowerCase();
- l("migrating", username);
-
- try {
- const multi = await db
- .multi()
- .set(`user:${username}`, id)
- .set(`user:${user.pubkey}`, id)
- .set(`user:${id}`, JSON.stringify(user));
-
- await multi.exec();
-
- await archive.del(`user:${username}`);
- await archive.del(`user:${user.pubkey}`);
- await archive.del(`user:${id}`);
-
- await s(`${id}:contacts`, (await ga(`${id}:contacts`)) || []);
- await archive.del(`${id}:contacts`);
-
- await s(
- `credit:bitcoin:${id}`,
- (await ga(`credit:bitcoin:${id}`)) || 0,
- );
- await archive.del(`credit:bitcoin:${id}`);
-
- await s(
- `credit:lightning:${id}`,
- (await ga(`credit:lightning:${id}`)) || 0,
- );
- await archive.del(`credit:lightning:${id}`);
-
- await s(`${id}:lastlen`, (await ga(`${id}:lastlen`)) || 0);
- await archive.del(`${id}:lastlen`);
- await s(`${id}:cindex`, (await ga(`${id}:cindex`)) || 0);
- await archive.del(`${id}:cindex`);
- await s(`balance:${id}`, (await ga(`balance:${id}`)) || 0);
- await archive.del(`balance:${id}`);
- await s(`pending:${id}`, (await ga(`pending:${id}`)) || 0);
- await archive.del(`pending:${id}`);
-
- let pid;
- while ((pid = await archive.rPop(`${id}:payments`))) {
- const p = await ga(`payment:${pid}`);
- const pos = await db.lPos(`${id}:payments`, pid);
- if (!p || pos) continue;
- if (p.type === types.internal && p.ref) {
- const recipient = await g(`user:${p.ref}`);
- if (!recipient) queued[p.ref] = true;
- }
-
- await db.lPush(`${id}:payments`, pid);
- await s(`payment:${pid}`, p);
-
- await archive.del(`payment:${pid}`);
- }
- await archive.del(`${id}:payments`);
-
- let iid;
- while ((iid = await archive.rPop(`${id}:invoices`))) {
- const inv = await ga(`invoice:${iid}`);
- const pos = await db.lPos(`${id}:invoices`, iid);
- if (!inv || pos) continue;
- await db.lPush(`${id}:invoices`, iid);
- await s(`invoice:${iid}`, inv);
-
- await archive.del(`invoice:${iid}`);
- }
- await archive.del(`${id}:invoices`);
-
- l("done migrating", username);
- } catch (e) {
- warn("failed to migrate", username, e.message, line());
- }
-
- delete migrating[id];
- return user;
- }
- } catch (e) {
- delete migrating[id];
- throw e;
- }
+ const k = id?.replace(/\s/g, "").toLowerCase();
+ let user = await g(`user:${k}`);
+ if (typeof user === "string") user = await g(`user:${user}`);
+ return user;
}
-const keepMigrating = async () => {
- try {
- if (Object.keys(queued).length) {
- const next = Object.keys(queued)[0];
- await migrate(next);
- }
- } catch (e) {
- err("problem migrating", e.message);
- }
-
- setTimeout(keepMigrating, 1000);
-};
-
-keepMigrating();
-
export default migrate;
diff --git a/lib/payments.ts b/lib/payments.ts
index d9833c96..ad39f81c 100644
--- a/lib/payments.ts
+++ b/lib/payments.ts
@@ -26,23 +26,14 @@ import { bech32 } from "bech32";
import got from "got";
import { v4 } from "uuid";
+import { PaymentType } from "$lib/types";
+
const bc = rpc(config.bitcoin);
const lq = rpc(config.liquid);
const { URL } = process.env;
const dust = 547;
-export const types = {
- internal: "internal",
- bitcoin: "bitcoin",
- lightning: "lightning",
- fund: "fund",
- liquid: "liquid",
- ecash: "ecash",
- reconcile: "reconcile",
- bolt12: "bolt12",
-};
-
export const debit = async ({
aid = undefined,
hash,
@@ -50,7 +41,7 @@ export const debit = async ({
fee = 0,
memo = undefined,
user,
- type = types.internal,
+ type = PaymentType.internal,
rate = undefined,
}) => {
amount = parseInt(amount);
@@ -69,7 +60,7 @@ export const debit = async ({
const userLimit = await g("limit");
const frozen =
(await g("hardfreeze")) ||
- ((await g("freeze")) && type !== types.internal) ||
+ ((await g("freeze")) && type !== PaymentType.internal) ||
blacklisted;
if (frozen || (amount > userLimit && !whitelisted) || amount > serverLimit) {
@@ -97,7 +88,7 @@ export const debit = async ({
let iid;
if (invoice) {
- if (invoice.received >= amount && invoice.type !== types.bolt12)
+ if (invoice.received >= amount && invoice.type !== PaymentType.bolt12)
fail("Invoice already paid");
({ id: iid } = invoice);
@@ -119,8 +110,8 @@ export const debit = async ({
if (!amount || amount < 0) fail("Amount must be greater than zero");
let creditType = type;
- if (creditType === types.bolt12) creditType = types.lightning;
- let ourfee: any = [types.bitcoin, types.liquid, types.lightning].includes(
+ if (creditType === PaymentType.bolt12) creditType = PaymentType.lightning;
+ let ourfee: any = [PaymentType.bitcoin, PaymentType.liquid, PaymentType.lightning].includes(
type,
)
? Math.round((amount + fee + tip) * config.fee)
@@ -170,7 +161,7 @@ export const debit = async ({
l(user.username, "sent", type, amount);
//emit(user.id, "payment", p);
- if (![types.lightning, types.bolt12].includes(type)) nwcNotify(p, user);
+ if (![PaymentType.lightning, PaymentType.bolt12].includes(type)) nwcNotify(p, user);
return p;
};
@@ -180,13 +171,13 @@ export const credit = async ({
amount,
memo = "",
ref = "",
- type = types.internal,
+ type = PaymentType.internal,
aid = undefined,
}) => {
amount = parseInt(amount) || 0;
let inv;
- if (type === types.bolt12) {
+ if (type === PaymentType.bolt12) {
const { invoices } = await ln.listinvoices({ invstring: hash });
const { local_offer_id } = invoices[0];
inv = await getInvoice(local_offer_id);
@@ -205,7 +196,7 @@ export const credit = async ({
if (!memo) ({ memo } = inv);
if (memo && memo.length > 5000) fail("memo too long");
if (amount < 0 || tip < 0) fail("Invalid amount");
- if (type === types.internal) amount += tip;
+ if (type === PaymentType.internal) amount += tip;
const user = await getUser(inv.uid);
const { id: uid, currency } = user;
@@ -244,7 +235,7 @@ export const credit = async ({
items: undefined,
};
- if ([types.bitcoin, types.liquid].includes(type)) inv.pending += amount;
+ if ([PaymentType.bitcoin, PaymentType.liquid].includes(type)) inv.pending += amount;
else {
inv.received += amount;
inv.preimage = ref;
@@ -252,7 +243,7 @@ export const credit = async ({
}
let balanceKey = "balance";
- if ([types.bitcoin, types.liquid].includes(type)) {
+ if ([PaymentType.bitcoin, PaymentType.liquid].includes(type)) {
const [txid, vout] = ref.split(":").slice(-2);
p.confirmed = false;
balanceKey = "pending";
@@ -264,8 +255,8 @@ export const credit = async ({
const m = await db.multi();
let creditType = type;
- if (creditType === types.bolt12) creditType = types.lightning;
- if ([types.bitcoin, types.liquid, types.lightning].includes(creditType))
+ if (creditType === PaymentType.bolt12) creditType = PaymentType.lightning;
+ if ([PaymentType.bitcoin, PaymentType.liquid, PaymentType.lightning].includes(creditType))
m.incrBy(`credit:${creditType}:${uid}`, Math.round(amount * config.fee));
m.set(`invoice:${inv.id}`, JSON.stringify(inv))
@@ -359,11 +350,11 @@ export const decode = async (hex) => {
let tx;
try {
tx = await bc.decodeRawTransaction(hex);
- type = types.bitcoin;
+ type = PaymentType.bitcoin;
} catch (e) {
try {
tx = await lq.decodeRawTransaction(hex);
- type = types.liquid;
+ type = PaymentType.liquid;
} catch (e) {
err("invalid hex", hex);
fail("unrecognized tx");
@@ -393,7 +384,7 @@ export const sendOnchain = async (params) => {
await node.walletPassphrase(config[type].walletpass, 300);
({ hex } = await node.signRawTransactionWithWallet(
- type === types.liquid ? await node.blindRawTransaction(hex) : hex,
+ type === PaymentType.liquid ? await node.blindRawTransaction(hex) : hex,
));
}
@@ -406,7 +397,7 @@ export const sendOnchain = async (params) => {
let fee = 0;
let change = 0;
- if (type === types.liquid) {
+ if (type === PaymentType.liquid) {
for (const {
asset,
scriptPubKey: { address, type },
@@ -493,7 +484,7 @@ export const sendKeysend = async ({
fee,
memo,
user,
- type: types.lightning,
+ type: PaymentType.lightning,
});
const r = await ln.keysend({
@@ -551,7 +542,7 @@ export const sendLightning = async ({
fee,
memo,
user,
- type: types.lightning,
+ type: PaymentType.lightning,
});
await db.sAdd("pending", pr);
@@ -612,11 +603,11 @@ export const sendInternal = async ({
const getAddressType = async (a) => {
try {
await bc.getAddressInfo(a);
- return types.bitcoin;
+ return PaymentType.bitcoin;
} catch (e) {
try {
await lq.getAddressInfo(a);
- return types.liquid;
+ return PaymentType.liquid;
} catch (e) {
fail("unrecognized address");
}
@@ -640,14 +631,14 @@ export const build = async ({
if (amount < 0) fail("invalid amount");
const fees: any =
- type === types.liquid
+ type === PaymentType.liquid
? { fastestFee: 0.1, halfHourFee: 0.1, hourFee: 0.1 }
: await fetch(`${api[type]}/fees/recommended`).then((r) => r.json());
fees.hourFee = fees.halfHourFee;
fees.halfHourFee = fees.fastestFee;
- if (type === types.bitcoin) {
+ if (type === PaymentType.bitcoin) {
fees.fastestFee = Math.round(fees.fastestFee * 1.1);
if (fees.fastestFee === fees.halfHourFee) fees.fastestFee++;
if (fees.hourFee === fees.halfHourFee) fees.hourFee--;
@@ -663,7 +654,7 @@ export const build = async ({
let outs = [{ [address]: btc(amount) }];
- if (type === types.liquid)
+ if (type === PaymentType.liquid)
outs = outs.map((o) => ({ ...o, asset: config.liquid.btc }));
let raw = await node.createRawTransaction([], outs, 0, replaceable);
@@ -789,7 +780,7 @@ export const reconcile = async (account, initial = false) => {
if (total > balance) {
const inv = {
memo,
- type: types.reconcile,
+ type: PaymentType.reconcile,
hash,
amount,
uid,
@@ -799,7 +790,7 @@ export const reconcile = async (account, initial = false) => {
await credit({
hash,
amount,
- type: types.reconcile,
+ type: PaymentType.reconcile,
aid: id,
});
} else if (total < balance) {
@@ -809,7 +800,7 @@ export const reconcile = async (account, initial = false) => {
hash: v4(),
memo,
user,
- type: types.reconcile,
+ type: PaymentType.reconcile,
});
}
} catch (e) {
@@ -883,7 +874,7 @@ const reverse = async (p) => {
await db.reverse(
`payment:${p.id}`,
`balance:${p.uid}`,
- `credit:${types.lightning}:${p.uid}`,
+ `credit:${PaymentType.lightning}:${p.uid}`,
`payment:${p.hash}`,
`${p.uid}:payments`,
p.id,
diff --git a/lib/types.ts b/lib/types.ts
new file mode 100644
index 00000000..e878dfb8
--- /dev/null
+++ b/lib/types.ts
@@ -0,0 +1,78 @@
+export interface User {
+ about: string;
+ admin: string;
+ anon: string;
+ autowithdraw: string;
+ balance: string;
+ banner: string;
+ currencies: string;
+ currency: string;
+ destination: string;
+ display: string;
+ email: string;
+ fiat: string;
+ followers: string;
+ follows: string;
+ haspin: string;
+ hasprinter: string;
+ hidepay: string;
+ id: string;
+ index: string;
+ keys: string;
+ language: string;
+ linked: string;
+ locktime: string;
+ memoPrompt: string;
+ nip5: string;
+ notify: string;
+ npub: string;
+ nsec: string;
+ nwc: string;
+ payments: string;
+ picture: string;
+ profile: string;
+ prompt: string;
+ pubkey: string;
+ push: string;
+ reserve: string;
+ seed: string;
+ shopifyStore: string;
+ shopifyToken: string;
+ theme: string;
+ threshold: string;
+ twofa: string;
+ username: string;
+ verified: string;
+}
+
+export enum PaymentType {
+ internal = "internal",
+ bitcoin = "bitcoin",
+ lightning = "lightning",
+ fund = "fund",
+ liquid = "liquid",
+ ecash = "ecash",
+ reconcile = "reconcile",
+ bolt12 = "bolt12",
+}
+
+export interface Payment {
+ id: string;
+ aid: string;
+ amount: number;
+ fee: number;
+ hash: string;
+ hex?: string;
+ ourfee: number;
+ memo?: string;
+ iid: string;
+ uid: string;
+ confirmed: boolean;
+ rate: number;
+ currency: string;
+ type: PaymentType;
+ ref: string;
+ tip?: number;
+ created: number;
+ user?: User;
+}
diff --git a/lib/utils.ts b/lib/utils.ts
index 79b95e62..018dc92e 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -1,9 +1,6 @@
import config from "$config";
-import { g, s } from "$lib/db";
+import { g } from "$lib/db";
import locales from "$lib/locales/index";
-import migrate from "$lib/migrate";
-import { bytesToHex, randomBytes } from "@noble/hashes/utils";
-import { getPublicKey } from "nostr";
const { URL } = process.env;
@@ -51,32 +48,10 @@ export const bip21 = (address, { amount, memo, tip, type }) => {
};
export const getUser = async (username, fields = undefined) => {
- let update;
if (username === "undefined") fail("invalid user");
- const user = await migrate(username);
- if (user && !user.anon && !user.nwc) {
- user.nwc = bytesToHex(randomBytes(32));
- await s(getPublicKey(user.nwc), user.id);
- update = true;
- }
-
- if (user?.profile) {
- user.picture = `https://coinos.io/api/public/${user.profile}.webp`;
- delete user.profile;
-
- if (user.banner) {
- user.banner = `https://coinos.io/api/public/${user.banner}.webp`;
- }
- update = true;
- }
-
- if (user?.address) {
- user.about = user.address;
- delete user.address;
- update = true;
- }
-
- if (update) s(`user:${user.id}`, user);
+ const k = username?.replace(/\s/g, "").toLowerCase();
+ let user = await g(`user:${k}`);
+ if (typeof user === "string") user = await g(`user:${user}`);
return fields && user ? pick(user, fields) : user;
};
diff --git a/routes/ecash.ts b/routes/ecash.ts
index e5039aa4..e4898358 100644
--- a/routes/ecash.ts
+++ b/routes/ecash.ts
@@ -1,12 +1,14 @@
import { db, g, s } from "$lib/db";
import { check, claim, get, mint } from "$lib/ecash";
import { err, l } from "$lib/logging";
-import { credit, debit, types } from "$lib/payments";
+import { credit, debit } from "$lib/payments";
import { emit } from "$lib/sockets";
import { bail, fail } from "$lib/utils";
import { getEncodedToken } from "@cashu/cashu-ts";
import { v4 } from "uuid";
-const { ecash: type } = types;
+
+import { PaymentType } from "$lib/types";
+const { ecash: type } = PaymentType;
Error.stackTraceLimit = 100; // Set this to the desired limit
@@ -97,7 +99,7 @@ export default {
try {
amount = Math.round(amount / 1000);
const ref = preimage;
- const { lightning: type } = types;
+ const { lightning: type } = PaymentType;
if (user.username !== "mint") fail("unauthorized");
const { id: uid, currency } = user;
const ourfee = await db.debit(
diff --git a/routes/lnurl.ts b/routes/lnurl.ts
index 05d369fc..294e6d7c 100644
--- a/routes/lnurl.ts
+++ b/routes/lnurl.ts
@@ -4,12 +4,13 @@ import ln from "$lib/ln";
import { err, warn } from "$lib/logging";
import { serverPubkey } from "$lib/nostr";
import { credit } from "$lib/payments";
-import { types } from "$lib/payments";
import { bail, fail, getInvoice, getUser } from "$lib/utils";
import { bech32 } from "bech32";
import got from "got";
import { v4 } from "uuid";
+import { PaymentType } from "$lib/types";
+
const { URL } = process.env;
const host = URL.split("/").at(-1);
@@ -124,7 +125,7 @@ export default {
invoice: {
amount: Math.round(amount / 1000),
memo: metadata,
- type: types.lightning,
+ type: PaymentType.lightning,
},
user,
});
@@ -158,7 +159,13 @@ export default {
let p;
if (invoice) {
const { hash } = invoice;
- p = await credit({ hash, amount, memo: id, ref: id, type: types.fund });
+ p = await credit({
+ hash,
+ amount,
+ memo: id,
+ ref: id,
+ type: PaymentType.fund,
+ });
} else {
await ln.xpay({
invstring: pr.replace(/\s/g, "").toLowerCase(),
@@ -173,7 +180,7 @@ export default {
confirmed: true,
rate: rates.USD,
currency: "USD",
- type: types.fund,
+ type: PaymentType.fund,
ref: id,
created: Date.now(),
};
diff --git a/routes/payments.ts b/routes/payments.ts
index 9282723a..e5af18ee 100644
--- a/routes/payments.ts
+++ b/routes/payments.ts
@@ -13,7 +13,6 @@ import {
sendInternal,
sendLightning,
sendOnchain,
- types,
} from "$lib/payments";
import { emit } from "$lib/sockets";
import {
@@ -30,6 +29,8 @@ import rpc from "@coinos/rpc";
import got from "got";
import { v4 } from "uuid";
+import { PaymentType } from "$lib/types";
+
import ln from "$lib/ln";
const { URL } = process.env;
@@ -77,7 +78,7 @@ export default {
sender: user,
});
} else if (fund) {
- p = await debit({ hash, amount, memo: fund, user, type: types.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);
@@ -115,7 +116,7 @@ export default {
return p;
}
if (p.created < start || p.created > end) return;
- if (p.type === types.internal) p.with = await getUser(p.ref, fields);
+ if (p.type === PaymentType.internal) p.with = await getUser(p.ref, fields);
return p;
}),
)
@@ -164,7 +165,7 @@ export default {
params: { hash },
} = req;
const p = await getPayment(hash);
- if (p?.type === types.internal) p.with = await getUser(p.ref, fields);
+ if (p?.type === PaymentType.internal) p.with = await getUser(p.ref, fields);
res.send(p);
} catch (e) {
console.log(e);
@@ -285,7 +286,7 @@ export default {
amount,
memo: id,
ref: id,
- type: types.fund,
+ type: PaymentType.fund,
});
await db.lPush(`fund:${id}:payments`, payment.id);
@@ -311,7 +312,7 @@ export default {
for (const { address, amount, asset, category, vout } of details) {
if (!address) continue;
- if (type === types.liquid && asset !== config.liquid.btc) continue;
+ if (type === PaymentType.liquid && asset !== config.liquid.btc) continue;
if (category === "send") {
const p = await getPayment(txid);
diff --git a/routes/users.ts b/routes/users.ts
index 106cfd4a..515e64f0 100644
--- a/routes/users.ts
+++ b/routes/users.ts
@@ -6,7 +6,7 @@ import { db, g, s } from "$lib/db";
import { err, l, warn } from "$lib/logging";
import { mail, templates } from "$lib/mail";
import { getNostrUser, getProfile, serverPubkey } from "$lib/nostr";
-import { reconcile, types } from "$lib/payments";
+import { reconcile } from "$lib/payments";
import register from "$lib/register";
import { emit } from "$lib/sockets";
import upload from "$lib/upload";
@@ -19,6 +19,8 @@ import { getPublicKey, nip19, verifyEvent } from "nostr-tools";
import { authenticator } from "otplib";
import { v4 } from "uuid";
+import type { Payment, PaymentType } from "$lib/types";
+
export default {
upload,
@@ -465,7 +467,7 @@ export default {
await Promise.all(
payments.reverse().map(async (id) => await g(`payment:${id}`)),
)
- ).filter((p) => p && p.type === types.internal && p.ref)) {
+ ).filter((p) => p && p.type === PaymentType.internal && p.ref)) {
if (ref === id) continue;
const i = contacts.findIndex((c) => c && c.id === ref);
if (~i) contacts.splice(i, 1);
@@ -817,6 +819,16 @@ export default {
async app(req, res) {
const { pubkey } = req.params;
const app = await g(`app:${pubkey}`);
+
+ let payments = (await db.lRange(`${pubkey}:payments`, 0, -1)) || [];
+ payments = await Promise.all(payments.map((hash) => g(`payment:${hash}`)));
+
+ await Promise.all(
+ payments.map(async (p: Payment) => (p.user = await g(`user:${p.uid}`))),
+ );
+
+ app.payments = payments.filter((p) => p);
+
res.send(app);
},
diff --git a/tsconfig.json b/tsconfig.json
index 330e2915..2eb42537 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,6 +18,7 @@
// Some stricter flags
"noUnusedLocals": true,
"noUnusedParameters": true,
+ "noAssignInExpressions": false,
"baseUrl": ".",
"paths": {