expected fees
This commit is contained in:
parent
df4d7464da
commit
9e3086df0d
7 changed files with 48 additions and 15 deletions
|
|
@ -1472,12 +1472,14 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
### PayAppUserInvoiceRequest
|
### PayAppUserInvoiceRequest
|
||||||
- __amount__: _number_
|
- __amount__: _number_
|
||||||
- __debit_npub__: _string_ *this field is optional
|
- __debit_npub__: _string_ *this field is optional
|
||||||
|
- __expected_fees__: _[CumulativeFees](#CumulativeFees)_ *this field is optional
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
- __user_identifier__: _string_
|
- __user_identifier__: _string_
|
||||||
|
|
||||||
### PayInvoiceRequest
|
### PayInvoiceRequest
|
||||||
- __amount__: _number_
|
- __amount__: _number_
|
||||||
- __debit_npub__: _string_ *this field is optional
|
- __debit_npub__: _string_ *this field is optional
|
||||||
|
- __expected_fees__: _[CumulativeFees](#CumulativeFees)_ *this field is optional
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
|
|
||||||
### PayInvoiceResponse
|
### PayInvoiceResponse
|
||||||
|
|
|
||||||
|
|
@ -555,15 +555,17 @@ type PayAddressResponse struct {
|
||||||
Txid string `json:"txId"`
|
Txid string `json:"txId"`
|
||||||
}
|
}
|
||||||
type PayAppUserInvoiceRequest struct {
|
type PayAppUserInvoiceRequest struct {
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
Debit_npub string `json:"debit_npub"`
|
Debit_npub string `json:"debit_npub"`
|
||||||
Invoice string `json:"invoice"`
|
Expected_fees *CumulativeFees `json:"expected_fees"`
|
||||||
User_identifier string `json:"user_identifier"`
|
Invoice string `json:"invoice"`
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
}
|
}
|
||||||
type PayInvoiceRequest struct {
|
type PayInvoiceRequest struct {
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
Debit_npub string `json:"debit_npub"`
|
Debit_npub string `json:"debit_npub"`
|
||||||
Invoice string `json:"invoice"`
|
Expected_fees *CumulativeFees `json:"expected_fees"`
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
}
|
}
|
||||||
type PayInvoiceResponse struct {
|
type PayInvoiceResponse struct {
|
||||||
Amount_paid int64 `json:"amount_paid"`
|
Amount_paid int64 `json:"amount_paid"`
|
||||||
|
|
|
||||||
|
|
@ -3262,15 +3262,17 @@ export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddr
|
||||||
export type PayAppUserInvoiceRequest = {
|
export type PayAppUserInvoiceRequest = {
|
||||||
amount: number
|
amount: number
|
||||||
debit_npub?: string
|
debit_npub?: string
|
||||||
|
expected_fees?: CumulativeFees
|
||||||
invoice: string
|
invoice: string
|
||||||
user_identifier: string
|
user_identifier: string
|
||||||
}
|
}
|
||||||
export type PayAppUserInvoiceRequestOptionalField = 'debit_npub'
|
export type PayAppUserInvoiceRequestOptionalField = 'debit_npub' | 'expected_fees'
|
||||||
export const PayAppUserInvoiceRequestOptionalFields: PayAppUserInvoiceRequestOptionalField[] = ['debit_npub']
|
export const PayAppUserInvoiceRequestOptionalFields: PayAppUserInvoiceRequestOptionalField[] = ['debit_npub', 'expected_fees']
|
||||||
export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & {
|
export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: PayAppUserInvoiceRequestOptionalField[]
|
checkOptionalsAreSet?: PayAppUserInvoiceRequestOptionalField[]
|
||||||
amount_CustomCheck?: (v: number) => boolean
|
amount_CustomCheck?: (v: number) => boolean
|
||||||
debit_npub_CustomCheck?: (v?: string) => boolean
|
debit_npub_CustomCheck?: (v?: string) => boolean
|
||||||
|
expected_fees_Options?: CumulativeFeesOptions
|
||||||
invoice_CustomCheck?: (v: string) => boolean
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
user_identifier_CustomCheck?: (v: string) => boolean
|
user_identifier_CustomCheck?: (v: string) => boolean
|
||||||
}
|
}
|
||||||
|
|
@ -3284,6 +3286,12 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o
|
||||||
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 ((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 (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.expected_fees === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('expected_fees')) {
|
||||||
|
const expected_feesErr = CumulativeFeesValidate(o.expected_fees, opts.expected_fees_Options, `${path}.expected_fees`)
|
||||||
|
if (expected_feesErr !== null) return expected_feesErr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
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`)
|
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
||||||
|
|
||||||
|
|
@ -3296,14 +3304,16 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o
|
||||||
export type PayInvoiceRequest = {
|
export type PayInvoiceRequest = {
|
||||||
amount: number
|
amount: number
|
||||||
debit_npub?: string
|
debit_npub?: string
|
||||||
|
expected_fees?: CumulativeFees
|
||||||
invoice: string
|
invoice: string
|
||||||
}
|
}
|
||||||
export type PayInvoiceRequestOptionalField = 'debit_npub'
|
export type PayInvoiceRequestOptionalField = 'debit_npub' | 'expected_fees'
|
||||||
export const PayInvoiceRequestOptionalFields: PayInvoiceRequestOptionalField[] = ['debit_npub']
|
export const PayInvoiceRequestOptionalFields: PayInvoiceRequestOptionalField[] = ['debit_npub', 'expected_fees']
|
||||||
export type PayInvoiceRequestOptions = OptionsBaseMessage & {
|
export type PayInvoiceRequestOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: PayInvoiceRequestOptionalField[]
|
checkOptionalsAreSet?: PayInvoiceRequestOptionalField[]
|
||||||
amount_CustomCheck?: (v: number) => boolean
|
amount_CustomCheck?: (v: number) => boolean
|
||||||
debit_npub_CustomCheck?: (v?: string) => boolean
|
debit_npub_CustomCheck?: (v?: string) => boolean
|
||||||
|
expected_fees_Options?: CumulativeFeesOptions
|
||||||
invoice_CustomCheck?: (v: string) => boolean
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
}
|
}
|
||||||
export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => {
|
export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => {
|
||||||
|
|
@ -3316,6 +3326,12 @@ export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoic
|
||||||
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 ((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 (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.expected_fees === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('expected_fees')) {
|
||||||
|
const expected_feesErr = CumulativeFeesValidate(o.expected_fees, opts.expected_fees_Options, `${path}.expected_fees`)
|
||||||
|
if (expected_feesErr !== null) return expected_feesErr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
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`)
|
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,7 @@ message PayAppUserInvoiceRequest {
|
||||||
string invoice = 2;
|
string invoice = 2;
|
||||||
int64 amount = 3;
|
int64 amount = 3;
|
||||||
optional string debit_npub = 4;
|
optional string debit_npub = 4;
|
||||||
|
optional CumulativeFees expected_fees = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SendAppUserToAppUserPaymentRequest {
|
message SendAppUserToAppUserPaymentRequest {
|
||||||
|
|
@ -466,6 +467,7 @@ message PayInvoiceRequest{
|
||||||
string invoice = 1;
|
string invoice = 1;
|
||||||
int64 amount = 2;
|
int64 amount = 2;
|
||||||
optional string debit_npub = 3;
|
optional string debit_npub = 3;
|
||||||
|
optional CumulativeFees expected_fees = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PayInvoiceResponse{
|
message PayInvoiceResponse{
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ export default class {
|
||||||
invoice: req.invoice,
|
invoice: req.invoice,
|
||||||
user_identifier: ctx.app_user_id,
|
user_identifier: ctx.app_user_id,
|
||||||
debit_npub: req.debit_npub,
|
debit_npub: req.debit_npub,
|
||||||
|
expected_fees: req.expected_fees,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -170,8 +170,8 @@ export class LiquidityProvider {
|
||||||
return Object.values(this.pendingPayments).reduce((a, b) => a + b, 0)
|
return Object.values(this.pendingPayments).reduce((a, b) => a + b, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
GetServiceFee = (amount: number) => {
|
GetServiceFee = (amount: number, f?: Types.CumulativeFees) => {
|
||||||
const fees = this.GetFees()
|
const fees = f ? f : this.GetFees()
|
||||||
const serviceFeeRate = fees.serviceFeeBps / 10000
|
const serviceFeeRate = fees.serviceFeeBps / 10000
|
||||||
const serviceFee = Math.ceil(serviceFeeRate * amount)
|
const serviceFee = Math.ceil(serviceFeeRate * amount)
|
||||||
return Math.max(serviceFee, fees.networkFeeFixed)
|
return Math.max(serviceFee, fees.networkFeeFixed)
|
||||||
|
|
@ -221,7 +221,8 @@ export class LiquidityProvider {
|
||||||
if (!this.IsReady()) {
|
if (!this.IsReady()) {
|
||||||
throw new Error("liquidity provider is not ready yet, disabled or unreachable")
|
throw new Error("liquidity provider is not ready yet, disabled or unreachable")
|
||||||
}
|
}
|
||||||
const providerServiceFee = this.GetServiceFee(decodedAmount)
|
const fees = this.GetFees()
|
||||||
|
const providerServiceFee = this.GetServiceFee(decodedAmount, fees)
|
||||||
this.pendingPayments[invoice] = decodedAmount + providerServiceFee
|
this.pendingPayments[invoice] = decodedAmount + providerServiceFee
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
if (!this.pendingPaymentsAck[invoice]) {
|
if (!this.pendingPaymentsAck[invoice]) {
|
||||||
|
|
@ -231,8 +232,9 @@ export class LiquidityProvider {
|
||||||
this.lastSeenBeacon = 0
|
this.lastSeenBeacon = 0
|
||||||
}, 1000 * 10)
|
}, 1000 * 10)
|
||||||
this.pendingPaymentsAck[invoice] = true
|
this.pendingPaymentsAck[invoice] = true
|
||||||
const res = await this.client.PayInvoice({ invoice, amount: 0 })
|
const res = await this.client.PayInvoice({ invoice, amount: 0, expected_fees: fees })
|
||||||
delete this.pendingPaymentsAck[invoice]
|
delete this.pendingPaymentsAck[invoice]
|
||||||
|
clearTimeout(timeout)
|
||||||
if (res.status === 'ERROR') {
|
if (res.status === 'ERROR') {
|
||||||
this.log("error paying invoice", res.reason)
|
this.log("error paying invoice", res.reason)
|
||||||
throw new Error(res.reason)
|
throw new Error(res.reason)
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,14 @@ export default class {
|
||||||
if (maybeBanned.locked) {
|
if (maybeBanned.locked) {
|
||||||
throw new Error("user is banned, cannot send payment")
|
throw new Error("user is banned, cannot send payment")
|
||||||
}
|
}
|
||||||
|
if (req.expected_fees) {
|
||||||
|
const { networkFeeFixed, serviceFeeBps } = req.expected_fees
|
||||||
|
const serviceFixed = this.settings.getSettings().lndSettings.feeFixedLimit
|
||||||
|
const serviceBps = this.settings.getSettings().serviceFeeSettings.outgoingAppUserInvoiceFeeBps
|
||||||
|
if (serviceFixed !== networkFeeFixed || serviceBps !== serviceFeeBps) {
|
||||||
|
throw new Error("fees do not match the expected fees")
|
||||||
|
}
|
||||||
|
}
|
||||||
const decoded = await this.lnd.DecodeInvoice(req.invoice)
|
const decoded = await this.lnd.DecodeInvoice(req.invoice)
|
||||||
if (decoded.numSatoshis !== 0 && req.amount !== 0) {
|
if (decoded.numSatoshis !== 0 && req.amount !== 0) {
|
||||||
throw new Error("invoice has value, do not provide amount the the request")
|
throw new Error("invoice has value, do not provide amount the the request")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue