From 19ee91cd5ff02ea206bca8a2463f4fe445980f52 Mon Sep 17 00:00:00 2001 From: boufni95 Date: Mon, 23 Sep 2024 15:48:09 +0000 Subject: [PATCH] fix rules wiring --- datasource.js | 5 ++-- proto/autogenerated/client.md | 2 ++ proto/autogenerated/go/types.go | 6 +++-- proto/autogenerated/ts/types.ts | 20 ++++++++++++---- proto/service/structs.proto | 2 ++ src/services/main/debitManager.ts | 2 +- src/services/main/paymentManager.ts | 12 +++++----- .../migrations/1727105758354-debit_to_pub.ts | 23 +++++++++++++++++++ src/services/storage/migrations/runner.ts | 3 ++- src/services/storage/paymentStorage.ts | 10 ++++---- 10 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 src/services/storage/migrations/1727105758354-debit_to_pub.ts diff --git a/datasource.js b/datasource.js index 691c4f5b..f4dd3915 100644 --- a/datasource.js +++ b/datasource.js @@ -25,13 +25,14 @@ import { CreateInviteTokenTable1721751414878 } from './build/src/services/storag import { PaymentIndex1721760297610 } from './build/src/services/storage/migrations/1721760297610-payment_index.js' import { DebitAccess1726496225078 } from './build/src/services/storage/migrations/1726496225078-debit_access.js' import { DebitAccessFixes1726685229264 } from './build/src/services/storage/migrations/1726685229264-debit_access_fixes.js' +import { DebitToPub1727105758354 } from './build/src/services/storage/migrations/1727105758354-debit_to_pub.js' export default new DataSource({ type: "sqlite", database: "db.sqlite", // logging: true, - migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264], + migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354], entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider, InviteToken, DebitAccess], // synchronize: true, }) -//npx typeorm migration:generate ./src/services/storage/migrations/debit_access_fixes -d ./datasource.js \ No newline at end of file +//npx typeorm migration:generate ./src/services/storage/migrations/debit_to_pub -d ./datasource.js \ No newline at end of file diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index e0f51a45..6c0d00db 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -965,11 +965,13 @@ The nostr server will send back a message response, and inside the body there wi ### PayAppUserInvoiceRequest - __amount__: _number_ + - __debit_npub__: _string_ *this field is optional - __invoice__: _string_ - __user_identifier__: _string_ ### PayInvoiceRequest - __amount__: _number_ + - __debit_npub__: _string_ *this field is optional - __invoice__: _string_ ### PayInvoiceResponse diff --git a/proto/autogenerated/go/types.go b/proto/autogenerated/go/types.go index d7f24749..eb8371bf 100644 --- a/proto/autogenerated/go/types.go +++ b/proto/autogenerated/go/types.go @@ -367,12 +367,14 @@ type PayAddressResponse struct { } type PayAppUserInvoiceRequest struct { Amount int64 `json:"amount"` + Debit_npub string `json:"debit_npub"` Invoice string `json:"invoice"` User_identifier string `json:"user_identifier"` } type PayInvoiceRequest struct { - Amount int64 `json:"amount"` - Invoice string `json:"invoice"` + Amount int64 `json:"amount"` + Debit_npub string `json:"debit_npub"` + Invoice string `json:"invoice"` } type PayInvoiceResponse struct { Amount_paid int64 `json:"amount_paid"` diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index 1c3e5a27..c85e309e 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -2079,13 +2079,16 @@ export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddr export type PayAppUserInvoiceRequest = { amount: number + debit_npub?: string invoice: string user_identifier: string } -export const PayAppUserInvoiceRequestOptionalFields: [] = [] +export type PayAppUserInvoiceRequestOptionalField = 'debit_npub' +export const PayAppUserInvoiceRequestOptionalFields: PayAppUserInvoiceRequestOptionalField[] = ['debit_npub'] export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] + checkOptionalsAreSet?: PayAppUserInvoiceRequestOptionalField[] amount_CustomCheck?: (v: number) => boolean + debit_npub_CustomCheck?: (v?: string) => boolean invoice_CustomCheck?: (v: string) => boolean user_identifier_CustomCheck?: (v: string) => boolean } @@ -2096,6 +2099,9 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + if ((o.debit_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('debit_npub')) && typeof o.debit_npub !== 'string') return new Error(`${path}.debit_npub: is not a string`) + if (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`) + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) @@ -2107,12 +2113,15 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o export type PayInvoiceRequest = { amount: number + debit_npub?: string invoice: string } -export const PayInvoiceRequestOptionalFields: [] = [] +export type PayInvoiceRequestOptionalField = 'debit_npub' +export const PayInvoiceRequestOptionalFields: PayInvoiceRequestOptionalField[] = ['debit_npub'] export type PayInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] + checkOptionalsAreSet?: PayInvoiceRequestOptionalField[] amount_CustomCheck?: (v: number) => boolean + debit_npub_CustomCheck?: (v?: string) => boolean invoice_CustomCheck?: (v: string) => boolean } export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => { @@ -2122,6 +2131,9 @@ export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoic if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + if ((o.debit_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('debit_npub')) && typeof o.debit_npub !== 'string') return new Error(`${path}.debit_npub: is not a string`) + if (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`) + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) diff --git a/proto/service/structs.proto b/proto/service/structs.proto index 22ebe454..b1245465 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -215,6 +215,7 @@ message PayAppUserInvoiceRequest { string user_identifier = 1; string invoice = 2; int64 amount = 3; + optional string debit_npub = 4; } message SendAppUserToAppUserPaymentRequest { @@ -283,6 +284,7 @@ message DecodeInvoiceResponse{ message PayInvoiceRequest{ string invoice = 1; int64 amount = 2; + optional string debit_npub = 3; } message PayInvoiceResponse{ diff --git a/src/services/main/debitManager.ts b/src/services/main/debitManager.ts index 386a728e..a763f41e 100644 --- a/src/services/main/debitManager.ts +++ b/src/services/main/debitManager.ts @@ -225,7 +225,7 @@ export class DebitManager { return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } } } await this.validateAccessRules(authorization, app, appUser) - const payment = await this.applicationManager.PayAppUserInvoice(appId, { amount: 0, invoice: bolt11, user_identifier: appUserId }) + const payment = await this.applicationManager.PayAppUserInvoice(appId, { amount: 0, invoice: bolt11, user_identifier: appUserId, debit_npub: requestorPub }) await this.storage.debitStorage.IncrementDebitAccess(appUserId, requestorPub, payment.amount_paid + payment.service_fee + payment.network_fee) const op = this.newPaymentOperation(payment, bolt11) return { status: 'invoicePaid', op, app, appUser, debitRes: { res: 'ok', preimage: payment.preimage } } diff --git a/src/services/main/paymentManager.ts b/src/services/main/paymentManager.ts index 4e0723c0..862c5795 100644 --- a/src/services/main/paymentManager.ts +++ b/src/services/main/paymentManager.ts @@ -299,9 +299,9 @@ export default class { } let paymentInfo = { preimage: "", amtPaid: 0, networkFee: 0, serialId: 0 } if (internalInvoice) { - paymentInfo = await this.PayInternalInvoice(userId, internalInvoice, { payAmount, serviceFee }, linkedApplication) + paymentInfo = await this.PayInternalInvoice(userId, internalInvoice, { payAmount, serviceFee }, linkedApplication, req.debit_npub) } else { - paymentInfo = await this.PayExternalInvoice(userId, req.invoice, { payAmount, serviceFee, amountForLnd: req.amount }, linkedApplication) + paymentInfo = await this.PayExternalInvoice(userId, req.invoice, { payAmount, serviceFee, amountForLnd: req.amount }, linkedApplication, req.debit_npub) } if (isAppUserPayment && serviceFee > 0) { await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee, "fees") @@ -317,7 +317,7 @@ export default class { } } - async PayExternalInvoice(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, amountForLnd: number }, linkedApplication: Application) { + async PayExternalInvoice(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, amountForLnd: number }, linkedApplication: Application, debitNpub?: string) { if (this.settings.disableExternalPayments) { throw new Error("something went wrong sending payment, please try again later") } @@ -338,7 +338,7 @@ export default class { const pendingPayment = await this.storage.txQueue.PushToQueue({ dbTx: true, description: "payment started", exec: async tx => { await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + routingFeeLimit, invoice, tx) - return await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, { payAmount, serviceFee, networkFee: routingFeeLimit }, linkedApplication, provider, tx) + return await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, { payAmount, serviceFee, networkFee: routingFeeLimit }, linkedApplication, provider, tx, debitNpub) } }) this.log("ready to pay") @@ -361,7 +361,7 @@ export default class { } } - async PayInternalInvoice(userId: string, internalInvoice: UserReceivingInvoice, amounts: { payAmount: number, serviceFee: number }, linkedApplication: Application) { + async PayInternalInvoice(userId: string, internalInvoice: UserReceivingInvoice, amounts: { payAmount: number, serviceFee: number }, linkedApplication: Application, debitNpub?: string) { if (internalInvoice.paid_at_unix > 0) { throw new Error("this invoice was already paid") } @@ -370,7 +370,7 @@ export default class { await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement, internalInvoice.invoice) try { await this.invoicePaidCb(internalInvoice.invoice, payAmount, 'internal') - const newPayment = await this.storage.paymentStorage.AddInternalPayment(userId, internalInvoice.invoice, payAmount, serviceFee, linkedApplication) + const newPayment = await this.storage.paymentStorage.AddInternalPayment(userId, internalInvoice.invoice, payAmount, serviceFee, linkedApplication, debitNpub) this.utils.stateBundler.AddTxPoint('paidAnInvoice', payAmount, { used: 'internal', from: 'user' }) return { preimage: "", amtPaid: payAmount, networkFee: 0, serialId: newPayment.serial_id } } catch (err) { diff --git a/src/services/storage/migrations/1727105758354-debit_to_pub.ts b/src/services/storage/migrations/1727105758354-debit_to_pub.ts new file mode 100644 index 00000000..172c174a --- /dev/null +++ b/src/services/storage/migrations/1727105758354-debit_to_pub.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class DebitToPub1727105758354 implements MigrationInterface { + name = 'DebitToPub1727105758354' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`); + await queryRunner.query(`CREATE TABLE "temporary_user_invoice_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "paid_amount" integer NOT NULL, "routing_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "paymentIndex" integer NOT NULL DEFAULT (-1), "debit_to_pub" varchar, CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "temporary_user_invoice_payment"("serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex") SELECT "serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex" FROM "user_invoice_payment"`); + await queryRunner.query(`DROP TABLE "user_invoice_payment"`); + await queryRunner.query(`ALTER TABLE "temporary_user_invoice_payment" RENAME TO "user_invoice_payment"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`); + await queryRunner.query(`ALTER TABLE "user_invoice_payment" RENAME TO "temporary_user_invoice_payment"`); + await queryRunner.query(`CREATE TABLE "user_invoice_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "paid_amount" integer NOT NULL, "routing_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "paymentIndex" integer NOT NULL DEFAULT (-1), CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "user_invoice_payment"("serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex") SELECT "serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex" FROM "temporary_user_invoice_payment"`); + await queryRunner.query(`DROP TABLE "temporary_user_invoice_payment"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `); + } +} diff --git a/src/services/storage/migrations/runner.ts b/src/services/storage/migrations/runner.ts index d8acf9bb..e7080920 100644 --- a/src/services/storage/migrations/runner.ts +++ b/src/services/storage/migrations/runner.ts @@ -14,7 +14,8 @@ import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js' import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js' import { DebitAccess1726496225078 } from './1726496225078-debit_access.js' import { DebitAccessFixes1726685229264 } from './1726685229264-debit_access_fixes.js' -const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264] +import { DebitToPub1727105758354 } from './1727105758354-debit_to_pub.js' +const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354] const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825] export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise => { if (arg === 'fake_initial_migration') { diff --git a/src/services/storage/paymentStorage.ts b/src/services/storage/paymentStorage.ts index 4fd30a80..d5e3e7c1 100644 --- a/src/services/storage/paymentStorage.ts +++ b/src/services/storage/paymentStorage.ts @@ -154,7 +154,7 @@ export default class { }) } - async AddPendingExternalPayment(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, networkFee: number }, linkedApplication: Application, liquidityProvider: string | undefined, dbTx: DataSource | EntityManager): Promise { + async AddPendingExternalPayment(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, networkFee: number }, linkedApplication: Application, liquidityProvider: string | undefined, dbTx: DataSource | EntityManager, debitNpub?: string): Promise { const newPayment = dbTx.getRepository(UserInvoicePayment).create({ user: await this.userStorage.GetUser(userId, dbTx), paid_amount: amounts.payAmount, @@ -164,7 +164,8 @@ export default class { paid_at_unix: 0, internal: false, linkedApplication, - liquidityProvider + liquidityProvider, + debit_to_pub: debitNpub }) return dbTx.getRepository(UserInvoicePayment).save(newPayment) } @@ -185,7 +186,7 @@ export default class { }) } - async AddInternalPayment(userId: string, invoice: string, amount: number, serviceFees: number, linkedApplication: Application): Promise { + async AddInternalPayment(userId: string, invoice: string, amount: number, serviceFees: number, linkedApplication: Application, debitNpub?: string): Promise { const newPayment = this.DB.getRepository(UserInvoicePayment).create({ user: await this.userStorage.GetUser(userId), paid_amount: amount, @@ -194,7 +195,8 @@ export default class { service_fees: serviceFees, paid_at_unix: Math.floor(Date.now() / 1000), internal: true, - linkedApplication + linkedApplication, + debit_to_pub: debitNpub }) return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add internal invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` }) }