From 1eb3a1f6ea096aa9d08b1c70a03383dd57e7fca4 Mon Sep 17 00:00:00 2001 From: shocknet-justin Date: Fri, 12 Dec 2025 14:35:31 -0500 Subject: [PATCH] columns --- src/services/main/applicationManager.ts | 7 ++++--- src/services/main/index.ts | 17 ++++++++--------- src/services/main/offerManager.ts | 12 +++++------- .../storage/entity/UserReceivingInvoice.ts | 15 +++++---------- .../migrations/1765354000000-clink_requester.ts | 7 ++++--- src/services/storage/paymentStorage.ts | 7 ++++--- 6 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/services/main/applicationManager.ts b/src/services/main/applicationManager.ts index 14646746..c874d36a 100644 --- a/src/services/main/applicationManager.ts +++ b/src/services/main/applicationManager.ts @@ -7,7 +7,7 @@ import { ApplicationUser } from '../storage/entity/ApplicationUser.js' import { PubLogger, getLogger } from '../helpers/logger.js' import crypto from 'crypto' import { Application } from '../storage/entity/Application.js' -import { ZapInfo, ClinkRequester } from '../storage/entity/UserReceivingInvoice.js' +import { ZapInfo } from '../storage/entity/UserReceivingInvoice.js' import { nofferEncode, ndebitEncode, OfferPriceType, nmanageEncode } from '@shocknet/clink-sdk' import SettingsManager from './settingsManager.js' const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds @@ -185,7 +185,7 @@ export default class { return invoice } - async AddAppUserInvoice(appId: string, req: Types.AddAppUserInvoiceRequest, clinkRequester?: ClinkRequester): Promise { + async AddAppUserInvoice(appId: string, req: Types.AddAppUserInvoiceRequest, clinkRequester?: { pub: string, eventId: string }): Promise { const app = await this.storage.applicationStorage.GetApplication(appId) const log = getLogger({ appName: app.name }) const receiver = await this.storage.applicationStorage.GetApplicationUser(app, req.receiver_identifier) @@ -201,7 +201,8 @@ export default class { offerId: req.offer_string, payerData: req.payer_data?.data, rejectUnauthorized: req.rejectUnauthorized, token: req.token, blind: req.invoice_req.blind, - clinkRequester + clinkRequesterPub: clinkRequester?.pub, + clinkRequesterEventId: clinkRequester?.eventId } const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts) return { diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 41eb2e9b..dea44a6f 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -292,7 +292,7 @@ export default class { } // Send CLINK receipt if this invoice was from a noffer request try { - if (userInvoice.clink_requester) { + if (userInvoice.clink_requester_pub && userInvoice.clink_requester_event_id) { this.createClinkReceipt(log, userInvoice) } } catch (err: any) { @@ -440,13 +440,12 @@ export default class { } async createClinkReceipt(log: PubLogger, invoice: UserReceivingInvoice) { - const clinkRequester = invoice.clink_requester - if (!clinkRequester || !invoice.linkedApplication) { + if (!invoice.clink_requester_pub || !invoice.clink_requester_event_id || !invoice.linkedApplication) { return } log("📤 [CLINK RECEIPT] Sending payment receipt", { - toPub: clinkRequester.pub, - eventId: clinkRequester.eventId + toPub: invoice.clink_requester_pub, + eventId: invoice.clink_requester_event_id }) // Receipt payload - payer's wallet already has the preimage const content = JSON.stringify({ res: 'ok' }) @@ -456,14 +455,14 @@ export default class { kind: 21001, pubkey: "", tags: [ - ["p", clinkRequester.pub], - ["e", clinkRequester.eventId], + ["p", invoice.clink_requester_pub], + ["e", invoice.clink_requester_event_id], ["clink_version", "1"] ], } this.nostrSend( - { type: 'app', appId: clinkRequester.appId }, - { type: 'event', event, encrypt: { toPub: clinkRequester.pub } } + { type: 'app', appId: invoice.linkedApplication.app_id }, + { type: 'event', event, encrypt: { toPub: invoice.clink_requester_pub } } ) } diff --git a/src/services/main/offerManager.ts b/src/services/main/offerManager.ts index 9f3b92f3..ec21c6f4 100644 --- a/src/services/main/offerManager.ts +++ b/src/services/main/offerManager.ts @@ -10,7 +10,6 @@ import { UserOffer } from '../storage/entity/UserOffer.js'; import { LiquidityManager } from "./liquidityManager.js" import { NofferData, OfferPriceType, nofferEncode } from '@shocknet/clink-sdk'; import SettingsManager from "./settingsManager.js"; -import { ClinkRequester } from '../storage/entity/UserReceivingInvoice.js'; const mapToOfferConfig = (appUserId: string, offer: UserOffer, { pubkey, relay }: { pubkey: string, relay: string }): Types.OfferConfig => { const offerStr = offer.offer_id @@ -166,10 +165,9 @@ export class OfferManager { }) // Store requester info for sending receipt when invoice is paid - const clinkRequester: ClinkRequester = { + const clinkRequester = { pub: event.pub, - eventId: event.id, - appId: event.appId + eventId: event.id } const offerInvoice = await this.getNofferInvoice(offerReq, event.appId, clinkRequester) @@ -206,7 +204,7 @@ export class OfferManager { return } - async HandleDefaultUserOffer(offerReq: NofferData, appId: string, remote: number, { memo, expiry }: { memo?: string, expiry?: number }, clinkRequester?: ClinkRequester): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { + async HandleDefaultUserOffer(offerReq: NofferData, appId: string, remote: number, { memo, expiry }: { memo?: string, expiry?: number }, clinkRequester?: { pub: string, eventId: string }): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { const { amount_sats: amount, offer } = offerReq if (!amount || isNaN(amount) || amount < 10 || amount > remote) { return { success: false, code: 5, max: remote } @@ -219,7 +217,7 @@ export class OfferManager { return { success: true, invoice: res.invoice } } - async HandleUserOffer(offerReq: NofferData, appId: string, remote: number, clinkRequester?: ClinkRequester): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { + async HandleUserOffer(offerReq: NofferData, appId: string, remote: number, clinkRequester?: { pub: string, eventId: string }): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { const { amount_sats: amount, offer } = offerReq const userOffer = await this.storage.offerStorage.GetOffer(offer) const expiry = offerReq.expires_in_seconds ? offerReq.expires_in_seconds : undefined @@ -262,7 +260,7 @@ export class OfferManager { return { success: true, invoice: res.invoice } } - async getNofferInvoice(offerReq: NofferData, appId: string, clinkRequester?: ClinkRequester): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { + async getNofferInvoice(offerReq: NofferData, appId: string, clinkRequester?: { pub: string, eventId: string }): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { try { const { remote } = await this.lnd.ChannelBalance() let maxSendable = remote diff --git a/src/services/storage/entity/UserReceivingInvoice.ts b/src/services/storage/entity/UserReceivingInvoice.ts index 3d6b7056..186c91b4 100644 --- a/src/services/storage/entity/UserReceivingInvoice.ts +++ b/src/services/storage/entity/UserReceivingInvoice.ts @@ -9,11 +9,6 @@ export type ZapInfo = { description: string } -export type ClinkRequester = { - pub: string // requester's pubkey - eventId: string // original request event ID - appId: string // app context for nostrSend -} @Entity() @Index("recv_invoice_paid_serial", ["user.serial_id", "paid_at_unix", "serial_id"], { where: "paid_at_unix > 0" }) export class UserReceivingInvoice { @@ -86,11 +81,11 @@ export class UserReceivingInvoice { }) liquidityProvider?: string - @Column({ - nullable: true, - type: 'simple-json' - }) - clink_requester?: ClinkRequester + @Column({ nullable: true }) + clink_requester_pub?: string + + @Column({ nullable: true }) + clink_requester_event_id?: string @CreateDateColumn() created_at: Date diff --git a/src/services/storage/migrations/1765354000000-clink_requester.ts b/src/services/storage/migrations/1765354000000-clink_requester.ts index 01ee2030..3028dce9 100644 --- a/src/services/storage/migrations/1765354000000-clink_requester.ts +++ b/src/services/storage/migrations/1765354000000-clink_requester.ts @@ -4,12 +4,13 @@ export class ClinkRequester1765354000000 implements MigrationInterface { name = 'ClinkRequester1765354000000' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_receiving_invoice" ADD COLUMN "clink_requester" text`); + await queryRunner.query(`ALTER TABLE "user_receiving_invoice" ADD COLUMN "clink_requester_pub" varchar`); + await queryRunner.query(`ALTER TABLE "user_receiving_invoice" ADD COLUMN "clink_requester_event_id" varchar`); } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_receiving_invoice" DROP COLUMN "clink_requester"`); + await queryRunner.query(`ALTER TABLE "user_receiving_invoice" DROP COLUMN "clink_requester_pub"`); + await queryRunner.query(`ALTER TABLE "user_receiving_invoice" DROP COLUMN "clink_requester_event_id"`); } } - diff --git a/src/services/storage/paymentStorage.ts b/src/services/storage/paymentStorage.ts index 52a20613..4b27775b 100644 --- a/src/services/storage/paymentStorage.ts +++ b/src/services/storage/paymentStorage.ts @@ -3,7 +3,7 @@ import { And, Between, Equal, FindOperator, IsNull, LessThan, LessThanOrEqual, M import { User } from './entity/User.js'; import { UserTransactionPayment } from './entity/UserTransactionPayment.js'; import { EphemeralKeyType, UserEphemeralKey } from './entity/UserEphemeralKey.js'; -import { UserReceivingInvoice, ZapInfo, ClinkRequester } from './entity/UserReceivingInvoice.js'; +import { UserReceivingInvoice, ZapInfo } from './entity/UserReceivingInvoice.js'; import { UserReceivingAddress } from './entity/UserReceivingAddress.js'; import { Product } from './entity/Product.js'; import UserStorage from './userStorage.js'; @@ -14,7 +14,7 @@ import { Application } from './entity/Application.js'; import TransactionsQueue from "./db/transactionsQueue.js"; import { LoggedEvent } from './eventsLog.js'; import { StorageInterface } from './db/storageInterface.js'; -export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application, zapInfo?: ZapInfo, offerId?: string, payerData?: Record, rejectUnauthorized?: boolean, token?: string, blind?: boolean, clinkRequester?: ClinkRequester } +export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application, zapInfo?: ZapInfo, offerId?: string, payerData?: Record, rejectUnauthorized?: boolean, token?: string, blind?: boolean, clinkRequesterPub?: string, clinkRequesterEventId?: string } export const defaultInvoiceExpiry = 60 * 60 export default class { dbs: StorageInterface @@ -130,7 +130,8 @@ export default class { payer_data: options.payerData, rejectUnauthorized: options.rejectUnauthorized, bearer_token: options.token, - clink_requester: options.clinkRequester + clink_requester_pub: options.clinkRequesterPub, + clink_requester_event_id: options.clinkRequesterEventId }, txId) }