Skip to content

Commit

Permalink
Merge pull request #764 from shocknet/debits
Browse files Browse the repository at this point in the history
zaps in nip69
  • Loading branch information
shocknet-justin authored Oct 16, 2024
2 parents 28413fb + d31466c commit 30d7942
Show file tree
Hide file tree
Showing 10 changed files with 31 additions and 14 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"grpc-tools": "^1.12.4",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"nostr-tools": "github:shocknet/nostr-tools#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
"nostr-tools": "github:shocknet/nostr-tools#da188cd4bd195f44cc690074a3898f354ae85100",
"pg": "^8.4.0",
"reflect-metadata": "^0.2.2",
"rimraf": "^3.0.2",
Expand Down
1 change: 1 addition & 0 deletions proto/autogenerated/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,7 @@ The nostr server will send back a message response, and inside the body there wi
### NewInvoiceRequest
- __amountSats__: _number_
- __memo__: _string_
- __zap__: _string_ *this field is optional

### NewInvoiceResponse
- __invoice__: _string_
Expand Down
1 change: 1 addition & 0 deletions proto/autogenerated/go/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ type NewAddressResponse struct {
type NewInvoiceRequest struct {
Amountsats int64 `json:"amountSats"`
Memo string `json:"memo"`
Zap string `json:"zap"`
}
type NewInvoiceResponse struct {
Invoice string `json:"invoice"`
Expand Down
10 changes: 8 additions & 2 deletions proto/autogenerated/ts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1990,12 +1990,15 @@ export const NewAddressResponseValidate = (o?: NewAddressResponse, opts: NewAddr
export type NewInvoiceRequest = {
amountSats: number
memo: string
zap?: string
}
export const NewInvoiceRequestOptionalFields: [] = []
export type NewInvoiceRequestOptionalField = 'zap'
export const NewInvoiceRequestOptionalFields: NewInvoiceRequestOptionalField[] = ['zap']
export type NewInvoiceRequestOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
checkOptionalsAreSet?: NewInvoiceRequestOptionalField[]
amountSats_CustomCheck?: (v: number) => boolean
memo_CustomCheck?: (v: string) => boolean
zap_CustomCheck?: (v?: string) => boolean
}
export const NewInvoiceRequestValidate = (o?: NewInvoiceRequest, opts: NewInvoiceRequestOptions = {}, path: string = 'NewInvoiceRequest::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
Expand All @@ -2007,6 +2010,9 @@ export const NewInvoiceRequestValidate = (o?: NewInvoiceRequest, opts: NewInvoic
if (typeof o.memo !== 'string') return new Error(`${path}.memo: is not a string`)
if (opts.memo_CustomCheck && !opts.memo_CustomCheck(o.memo)) return new Error(`${path}.memo: custom check failed`)

if ((o.zap || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('zap')) && typeof o.zap !== 'string') return new Error(`${path}.zap: is not a string`)
if (opts.zap_CustomCheck && !opts.zap_CustomCheck(o.zap)) return new Error(`${path}.zap: custom check failed`)

return null
}

Expand Down
1 change: 1 addition & 0 deletions proto/service/structs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ message PayAddressResponse{
message NewInvoiceRequest{
int64 amountSats = 1;
string memo = 2;
optional string zap = 3;
}

message NewInvoiceResponse{
Expand Down
3 changes: 2 additions & 1 deletion src/nostrMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import Main, { NofferData } from "./services/main/index.js"
import Main from "./services/main/index.js"
import Nostr from "./services/nostr/index.js"
import { NostrEvent, NostrSend, NostrSettings } from "./services/nostr/handler.js"
import * as Types from '../proto/autogenerated/ts/types.js'
import NewNostrTransport, { NostrRequest } from '../proto/autogenerated/ts/nostr_transport.js';
import { ERROR, getLogger } from "./services/helpers/logger.js";
import { NdebitData } from "nostr-tools/lib/types/nip68.js";
import { NofferData } from "nostr-tools/lib/types/nip69.js";

export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSettings: NostrSettings, onClientEvent: (e: { requestId: string }, fromPub: string) => void): { Stop: () => void, Send: NostrSend } => {
const log = getLogger({})
Expand Down
7 changes: 6 additions & 1 deletion src/services/main/applicationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import crypto from 'crypto'
import { Application } from '../storage/entity/Application.js'
import { nip69, nip19 } from 'nostr-tools'
import { LoadNosrtSettingsFromEnv } from '../nostr/index.js'
import { ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
const { SendNofferRequest } = nip69
const { nofferEncode, ndebitEncode, OfferPriceType } = nip19
const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds
Expand Down Expand Up @@ -188,7 +189,11 @@ export default class {
const receiver = await this.storage.applicationStorage.GetApplicationUser(app, req.receiver_identifier)
const { user: payer } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.payer_identifier, 0)
const cbUrl = req.http_callback_url || receiver.callback_url || ""
const opts: InboundOptionals = { callbackUrl: cbUrl, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
let zapInfo: ZapInfo | undefined = undefined
if (req.invoice_req.zap) {
zapInfo = this.paymentManager.validateZapEvent(req.invoice_req.zap, req.invoice_req.amountSats)
}
const opts: InboundOptionals = { callbackUrl: cbUrl, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app, zapInfo }
const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts)
return {
invoice: appUserInvoice.invoice
Expand Down
11 changes: 5 additions & 6 deletions src/services/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { AddressPaidCb, HtlcCb, InvoicePaidCb, NewBlockCb } from "../lnd/setting
import { ERROR, getLogger, PubLogger } from "../helpers/logger.js"
import AppUserManager from "./appUserManager.js"
import { Application } from '../storage/entity/Application.js'
import { UserReceivingInvoice } from '../storage/entity/UserReceivingInvoice.js'
import { UserReceivingInvoice, ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
import { UnsignedEvent } from 'nostr-tools'
import { NostrEvent, NostrSend } from '../nostr/handler.js'
import MetricsManager from '../metrics/index.js'
Expand All @@ -23,6 +23,7 @@ import { AdminManager } from "./adminManager.js"
import { Unlocker } from "./unlocker.js"
import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"
import { DebitManager } from "./debitManager.js"
import { NofferData } from "nostr-tools/lib/types/nip69.js"

type UserOperationsSub = {
id: string
Expand All @@ -32,7 +33,6 @@ type UserOperationsSub = {
newOutgoingTx: (operation: Types.UserOperation) => void
}
const appTag = "Lightning.Pub"
export type NofferData = { offer: string, amount?: number }

export default class {
storage: Storage
Expand Down Expand Up @@ -278,11 +278,12 @@ export default class {
tags,
}
log({ unsigned: event })
this.nostrSend({ type: 'app', appId: invoice.linkedApplication.app_id }, { type: 'event', event })
this.nostrSend({ type: 'app', appId: invoice.linkedApplication.app_id }, { type: 'event', event }, zapInfo.relays || undefined)
}

async getNofferInvoice(offerReq: NofferData, appId: string): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
try {

const { remote } = await this.lnd.ChannelBalance()
const { offer, amount } = offerReq
const split = offer.split(':')
Expand All @@ -292,7 +293,7 @@ export default class {
}
const res = await this.applicationManager.AddAppUserInvoice(appId, {
http_callback_url: "", payer_identifier: split[0], receiver_identifier: split[0],
invoice_req: { amountSats: amount, memo: "Default NIP-69 Offer" }
invoice_req: { amountSats: amount, memo: "Default NIP-69 Offer", zap: offerReq.zap }
})
return { success: true, invoice: res.invoice }
} else if (split[0] === 'p') {
Expand All @@ -319,8 +320,6 @@ export default class {
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
return
}


}

const codeToMessage = (code: number) => {
Expand Down
3 changes: 3 additions & 0 deletions src/services/main/paymentManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@ export default class {
if (!verified) {
throw new Error("nostr event not valid")
}
if (nostrEvent.kind !== 9734) {
throw new Error("nostr event not a zap event")
}
const p = this.parseTags("p", nostrEvent.tags, { required: true })
const e = this.parseTags("e", nostrEvent.tags)
const relays = this.parseTags("relays", nostrEvent.tags, { required: true, multiples: true })
Expand Down

0 comments on commit 30d7942

Please sign in to comment.