zaps in nip69
This commit is contained in:
parent
45f4f01bce
commit
c909ad3172
8 changed files with 25 additions and 12 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -32,7 +32,7 @@
|
||||||
"grpc-tools": "^1.12.4",
|
"grpc-tools": "^1.12.4",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nostr-tools": "github:shocknet/nostr-tools#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
"nostr-tools": "github:shocknet/nostr-tools#da188cd4bd195f44cc690074a3898f354ae85100",
|
||||||
"pg": "^8.4.0",
|
"pg": "^8.4.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|
@ -3803,8 +3803,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/nostr-tools": {
|
"node_modules/nostr-tools": {
|
||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
"resolved": "git+ssh://git@github.com/shocknet/nostr-tools.git#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
"resolved": "git+ssh://git@github.com/shocknet/nostr-tools.git#da188cd4bd195f44cc690074a3898f354ae85100",
|
||||||
"integrity": "sha512-NWYu4yx9UELd4M333r6Eirg0lKK9vyEiUW/8DDorZtxSlBdH4B9FqH8w7VJrG2LfPJABC89EH6+VNLz7RENCfg==",
|
"integrity": "sha512-kc41K75rXEnLhqIwlQmjaGsZ9yYTbyP8VW7B2Q+0U/pqaMyt25Nt0QCWiIYS04m0sanvD77OhmddvI1s2ntKog==",
|
||||||
"license": "Unlicense",
|
"license": "Unlicense",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/ciphers": "^0.5.1",
|
"@noble/ciphers": "^0.5.1",
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
"grpc-tools": "^1.12.4",
|
"grpc-tools": "^1.12.4",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nostr-tools": "github:shocknet/nostr-tools#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
"nostr-tools": "github:shocknet/nostr-tools#da188cd4bd195f44cc690074a3898f354ae85100",
|
||||||
"pg": "^8.4.0",
|
"pg": "^8.4.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|
|
||||||
|
|
@ -976,6 +976,7 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
### NewInvoiceRequest
|
### NewInvoiceRequest
|
||||||
- __amountSats__: _number_
|
- __amountSats__: _number_
|
||||||
- __memo__: _string_
|
- __memo__: _string_
|
||||||
|
- __zap__: _string_ *this field is optional
|
||||||
|
|
||||||
### NewInvoiceResponse
|
### NewInvoiceResponse
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,7 @@ type NewAddressResponse struct {
|
||||||
type NewInvoiceRequest struct {
|
type NewInvoiceRequest struct {
|
||||||
Amountsats int64 `json:"amountSats"`
|
Amountsats int64 `json:"amountSats"`
|
||||||
Memo string `json:"memo"`
|
Memo string `json:"memo"`
|
||||||
|
Zap string `json:"zap"`
|
||||||
}
|
}
|
||||||
type NewInvoiceResponse struct {
|
type NewInvoiceResponse struct {
|
||||||
Invoice string `json:"invoice"`
|
Invoice string `json:"invoice"`
|
||||||
|
|
|
||||||
|
|
@ -1949,12 +1949,15 @@ export const NewAddressResponseValidate = (o?: NewAddressResponse, opts: NewAddr
|
||||||
export type NewInvoiceRequest = {
|
export type NewInvoiceRequest = {
|
||||||
amountSats: number
|
amountSats: number
|
||||||
memo: string
|
memo: string
|
||||||
|
zap?: string
|
||||||
}
|
}
|
||||||
export const NewInvoiceRequestOptionalFields: [] = []
|
export type NewInvoiceRequestOptionalField = 'zap'
|
||||||
|
export const NewInvoiceRequestOptionalFields: NewInvoiceRequestOptionalField[] = ['zap']
|
||||||
export type NewInvoiceRequestOptions = OptionsBaseMessage & {
|
export type NewInvoiceRequestOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: []
|
checkOptionalsAreSet?: NewInvoiceRequestOptionalField[]
|
||||||
amountSats_CustomCheck?: (v: number) => boolean
|
amountSats_CustomCheck?: (v: number) => boolean
|
||||||
memo_CustomCheck?: (v: string) => boolean
|
memo_CustomCheck?: (v: string) => boolean
|
||||||
|
zap_CustomCheck?: (v?: string) => boolean
|
||||||
}
|
}
|
||||||
export const NewInvoiceRequestValidate = (o?: NewInvoiceRequest, opts: NewInvoiceRequestOptions = {}, path: string = 'NewInvoiceRequest::root.'): Error | null => {
|
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')
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
|
@ -1966,6 +1969,9 @@ export const NewInvoiceRequestValidate = (o?: NewInvoiceRequest, opts: NewInvoic
|
||||||
if (typeof o.memo !== 'string') return new Error(`${path}.memo: is not a string`)
|
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 (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
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,7 @@ message PayAddressResponse{
|
||||||
message NewInvoiceRequest{
|
message NewInvoiceRequest{
|
||||||
int64 amountSats = 1;
|
int64 amountSats = 1;
|
||||||
string memo = 2;
|
string memo = 2;
|
||||||
|
optional string zap = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NewInvoiceResponse{
|
message NewInvoiceResponse{
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import crypto from 'crypto'
|
||||||
import { Application } from '../storage/entity/Application.js'
|
import { Application } from '../storage/entity/Application.js'
|
||||||
import { nip69, nip19 } from 'nostr-tools'
|
import { nip69, nip19 } from 'nostr-tools'
|
||||||
import { LoadNosrtSettingsFromEnv } from '../nostr/index.js'
|
import { LoadNosrtSettingsFromEnv } from '../nostr/index.js'
|
||||||
|
import { ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
|
||||||
const { SendNofferRequest } = nip69
|
const { SendNofferRequest } = nip69
|
||||||
const { nofferEncode, ndebitEncode, OfferPriceType } = nip19
|
const { nofferEncode, ndebitEncode, OfferPriceType } = nip19
|
||||||
const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds
|
const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds
|
||||||
|
|
@ -187,7 +188,11 @@ export default class {
|
||||||
const receiver = await this.storage.applicationStorage.GetApplicationUser(app, req.receiver_identifier)
|
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 { user: payer } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.payer_identifier, 0)
|
||||||
const cbUrl = req.http_callback_url || receiver.callback_url || ""
|
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)
|
const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts)
|
||||||
return {
|
return {
|
||||||
invoice: appUserInvoice.invoice
|
invoice: appUserInvoice.invoice
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { AddressPaidCb, HtlcCb, InvoicePaidCb, NewBlockCb } from "../lnd/setting
|
||||||
import { ERROR, getLogger, PubLogger } from "../helpers/logger.js"
|
import { ERROR, getLogger, PubLogger } from "../helpers/logger.js"
|
||||||
import AppUserManager from "./appUserManager.js"
|
import AppUserManager from "./appUserManager.js"
|
||||||
import { Application } from '../storage/entity/Application.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 { UnsignedEvent } from 'nostr-tools'
|
||||||
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
||||||
import MetricsManager from '../metrics/index.js'
|
import MetricsManager from '../metrics/index.js'
|
||||||
|
|
@ -23,6 +23,7 @@ import { AdminManager } from "./adminManager.js"
|
||||||
import { Unlocker } from "./unlocker.js"
|
import { Unlocker } from "./unlocker.js"
|
||||||
import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"
|
import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"
|
||||||
import { DebitManager } from "./debitManager.js"
|
import { DebitManager } from "./debitManager.js"
|
||||||
|
import { NofferData } from "nostr-tools/lib/types/nip69.js"
|
||||||
|
|
||||||
type UserOperationsSub = {
|
type UserOperationsSub = {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -32,7 +33,6 @@ type UserOperationsSub = {
|
||||||
newOutgoingTx: (operation: Types.UserOperation) => void
|
newOutgoingTx: (operation: Types.UserOperation) => void
|
||||||
}
|
}
|
||||||
const appTag = "Lightning.Pub"
|
const appTag = "Lightning.Pub"
|
||||||
export type NofferData = { offer: string, amount?: number }
|
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
|
|
@ -283,6 +283,7 @@ export default class {
|
||||||
|
|
||||||
async getNofferInvoice(offerReq: NofferData, appId: string): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
|
async getNofferInvoice(offerReq: NofferData, appId: string): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { remote } = await this.lnd.ChannelBalance()
|
const { remote } = await this.lnd.ChannelBalance()
|
||||||
const { offer, amount } = offerReq
|
const { offer, amount } = offerReq
|
||||||
const split = offer.split(':')
|
const split = offer.split(':')
|
||||||
|
|
@ -292,7 +293,7 @@ export default class {
|
||||||
}
|
}
|
||||||
const res = await this.applicationManager.AddAppUserInvoice(appId, {
|
const res = await this.applicationManager.AddAppUserInvoice(appId, {
|
||||||
http_callback_url: "", payer_identifier: split[0], receiver_identifier: split[0],
|
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 }
|
return { success: true, invoice: res.invoice }
|
||||||
} else if (split[0] === 'p') {
|
} else if (split[0] === 'p') {
|
||||||
|
|
@ -319,8 +320,6 @@ export default class {
|
||||||
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeToMessage = (code: number) => {
|
const codeToMessage = (code: number) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue