Merge pull request #879 from shocknet/swaps-info
add time info to swaps
This commit is contained in:
commit
97de703feb
12 changed files with 135 additions and 75 deletions
|
|
@ -1,3 +1,14 @@
|
||||||
|
/**
|
||||||
|
* TypeORM DataSource used only by the TypeORM CLI (e.g. migration:generate).
|
||||||
|
*
|
||||||
|
* Migrations at runtime are run from src/services/storage/migrations/runner.ts (allMigrations),
|
||||||
|
* not from this file. The app never uses this DataSource to run migrations.
|
||||||
|
*
|
||||||
|
* Workflow: update the migrations array in this file *before* running
|
||||||
|
* migration:generate, so TypeORM knows the current schema (entities + existing migrations).
|
||||||
|
* We do not update this file immediately after adding a new migration; update it when you
|
||||||
|
* are about to generate the next migration.
|
||||||
|
*/
|
||||||
import { DataSource } from "typeorm"
|
import { DataSource } from "typeorm"
|
||||||
import { User } from "./build/src/services/storage/entity/User.js"
|
import { User } from "./build/src/services/storage/entity/User.js"
|
||||||
import { UserReceivingInvoice } from "./build/src/services/storage/entity/UserReceivingInvoice.js"
|
import { UserReceivingInvoice } from "./build/src/services/storage/entity/UserReceivingInvoice.js"
|
||||||
|
|
@ -50,6 +61,7 @@ import { ClinkRequester1765497600000 } from './build/src/services/storage/migrat
|
||||||
import { TrackedProviderHeight1766504040000 } from './build/src/services/storage/migrations/1766504040000-tracked_provider_height.js'
|
import { TrackedProviderHeight1766504040000 } from './build/src/services/storage/migrations/1766504040000-tracked_provider_height.js'
|
||||||
import { SwapsServiceUrl1768413055036 } from './build/src/services/storage/migrations/1768413055036-swaps_service_url.js'
|
import { SwapsServiceUrl1768413055036 } from './build/src/services/storage/migrations/1768413055036-swaps_service_url.js'
|
||||||
import { InvoiceSwaps1769529793283 } from './build/src/services/storage/migrations/1769529793283-invoice_swaps.js'
|
import { InvoiceSwaps1769529793283 } from './build/src/services/storage/migrations/1769529793283-invoice_swaps.js'
|
||||||
|
import { InvoiceSwapsFixes1769805357459 } from './build/src/services/storage/migrations/1769805357459-invoice_swaps_fixes.js'
|
||||||
|
|
||||||
export default new DataSource({
|
export default new DataSource({
|
||||||
type: "better-sqlite3",
|
type: "better-sqlite3",
|
||||||
|
|
@ -59,11 +71,11 @@ export default new DataSource({
|
||||||
PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043,
|
PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043,
|
||||||
UserOffer1733502626042, ManagementGrant1751307732346, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611,
|
UserOffer1733502626042, ManagementGrant1751307732346, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611,
|
||||||
AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098,
|
AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098,
|
||||||
TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036, InvoiceSwaps1769529793283],
|
TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036, InvoiceSwaps1769529793283, InvoiceSwapsFixes1769805357459],
|
||||||
|
|
||||||
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
||||||
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo,
|
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo,
|
||||||
TrackedProvider, InviteToken, DebitAccess, UserOffer, ManagementGrant, AppUserDevice, UserAccess, AdminSettings, TransactionSwap, InvoiceSwap],
|
TrackedProvider, InviteToken, DebitAccess, UserOffer, ManagementGrant, AppUserDevice, UserAccess, AdminSettings, TransactionSwap, InvoiceSwap],
|
||||||
// synchronize: true,
|
// synchronize: true,
|
||||||
})
|
})
|
||||||
//npx typeorm migration:generate ./src/services/storage/migrations/invoice_swaps_fixes -d ./datasource.js
|
//npx typeorm migration:generate ./src/services/storage/migrations/swap_timestamps -d ./datasource.js
|
||||||
|
|
@ -1383,17 +1383,18 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- __url__: _string_
|
- __url__: _string_
|
||||||
|
|
||||||
### InvoiceSwapOperation
|
### InvoiceSwapOperation
|
||||||
|
- __completed_at_unix__: _number_ *this field is optional
|
||||||
- __failure_reason__: _string_ *this field is optional
|
- __failure_reason__: _string_ *this field is optional
|
||||||
- __invoice_paid__: _string_
|
|
||||||
- __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional
|
- __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional
|
||||||
- __swap_operation_id__: _string_
|
- __quote__: _[InvoiceSwapQuote](#InvoiceSwapQuote)_
|
||||||
- __tx_id__: _string_
|
|
||||||
|
|
||||||
### InvoiceSwapQuote
|
### InvoiceSwapQuote
|
||||||
- __address__: _string_
|
- __address__: _string_
|
||||||
- __chain_fee_sats__: _number_
|
- __chain_fee_sats__: _number_
|
||||||
|
- __expires_at_block_height__: _number_
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
- __invoice_amount_sats__: _number_
|
- __invoice_amount_sats__: _number_
|
||||||
|
- __paid_at_unix__: _number_
|
||||||
- __service_fee_sats__: _number_
|
- __service_fee_sats__: _number_
|
||||||
- __service_url__: _string_
|
- __service_url__: _string_
|
||||||
- __swap_fee_sats__: _number_
|
- __swap_fee_sats__: _number_
|
||||||
|
|
@ -1408,7 +1409,7 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- __amount_sats__: _number_
|
- __amount_sats__: _number_
|
||||||
|
|
||||||
### InvoiceSwapsList
|
### InvoiceSwapsList
|
||||||
- __quotes__: ARRAY of: _[InvoiceSwapQuote](#InvoiceSwapQuote)_
|
- __current_block_height__: _number_
|
||||||
- __swaps__: ARRAY of: _[InvoiceSwapOperation](#InvoiceSwapOperation)_
|
- __swaps__: ARRAY of: _[InvoiceSwapOperation](#InvoiceSwapOperation)_
|
||||||
|
|
||||||
### LatestBundleMetricReq
|
### LatestBundleMetricReq
|
||||||
|
|
|
||||||
|
|
@ -360,17 +360,18 @@ type HttpCreds struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
}
|
}
|
||||||
type InvoiceSwapOperation struct {
|
type InvoiceSwapOperation struct {
|
||||||
|
Completed_at_unix int64 `json:"completed_at_unix"`
|
||||||
Failure_reason string `json:"failure_reason"`
|
Failure_reason string `json:"failure_reason"`
|
||||||
Invoice_paid string `json:"invoice_paid"`
|
|
||||||
Operation_payment *UserOperation `json:"operation_payment"`
|
Operation_payment *UserOperation `json:"operation_payment"`
|
||||||
Swap_operation_id string `json:"swap_operation_id"`
|
Quote *InvoiceSwapQuote `json:"quote"`
|
||||||
Tx_id string `json:"tx_id"`
|
|
||||||
}
|
}
|
||||||
type InvoiceSwapQuote struct {
|
type InvoiceSwapQuote struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Chain_fee_sats int64 `json:"chain_fee_sats"`
|
Chain_fee_sats int64 `json:"chain_fee_sats"`
|
||||||
|
Expires_at_block_height int64 `json:"expires_at_block_height"`
|
||||||
Invoice string `json:"invoice"`
|
Invoice string `json:"invoice"`
|
||||||
Invoice_amount_sats int64 `json:"invoice_amount_sats"`
|
Invoice_amount_sats int64 `json:"invoice_amount_sats"`
|
||||||
|
Paid_at_unix int64 `json:"paid_at_unix"`
|
||||||
Service_fee_sats int64 `json:"service_fee_sats"`
|
Service_fee_sats int64 `json:"service_fee_sats"`
|
||||||
Service_url string `json:"service_url"`
|
Service_url string `json:"service_url"`
|
||||||
Swap_fee_sats int64 `json:"swap_fee_sats"`
|
Swap_fee_sats int64 `json:"swap_fee_sats"`
|
||||||
|
|
@ -385,7 +386,7 @@ type InvoiceSwapRequest struct {
|
||||||
Amount_sats int64 `json:"amount_sats"`
|
Amount_sats int64 `json:"amount_sats"`
|
||||||
}
|
}
|
||||||
type InvoiceSwapsList struct {
|
type InvoiceSwapsList struct {
|
||||||
Quotes []InvoiceSwapQuote `json:"quotes"`
|
Current_block_height int64 `json:"current_block_height"`
|
||||||
Swaps []InvoiceSwapOperation `json:"swaps"`
|
Swaps []InvoiceSwapOperation `json:"swaps"`
|
||||||
}
|
}
|
||||||
type LatestBundleMetricReq struct {
|
type LatestBundleMetricReq struct {
|
||||||
|
|
|
||||||
|
|
@ -2123,43 +2123,39 @@ export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, pa
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InvoiceSwapOperation = {
|
export type InvoiceSwapOperation = {
|
||||||
|
completed_at_unix?: number
|
||||||
failure_reason?: string
|
failure_reason?: string
|
||||||
invoice_paid: string
|
|
||||||
operation_payment?: UserOperation
|
operation_payment?: UserOperation
|
||||||
swap_operation_id: string
|
quote: InvoiceSwapQuote
|
||||||
tx_id: string
|
|
||||||
}
|
}
|
||||||
export type InvoiceSwapOperationOptionalField = 'failure_reason' | 'operation_payment'
|
export type InvoiceSwapOperationOptionalField = 'completed_at_unix' | 'failure_reason' | 'operation_payment'
|
||||||
export const InvoiceSwapOperationOptionalFields: InvoiceSwapOperationOptionalField[] = ['failure_reason', 'operation_payment']
|
export const InvoiceSwapOperationOptionalFields: InvoiceSwapOperationOptionalField[] = ['completed_at_unix', 'failure_reason', 'operation_payment']
|
||||||
export type InvoiceSwapOperationOptions = OptionsBaseMessage & {
|
export type InvoiceSwapOperationOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: InvoiceSwapOperationOptionalField[]
|
checkOptionalsAreSet?: InvoiceSwapOperationOptionalField[]
|
||||||
|
completed_at_unix_CustomCheck?: (v?: number) => boolean
|
||||||
failure_reason_CustomCheck?: (v?: string) => boolean
|
failure_reason_CustomCheck?: (v?: string) => boolean
|
||||||
invoice_paid_CustomCheck?: (v: string) => boolean
|
|
||||||
operation_payment_Options?: UserOperationOptions
|
operation_payment_Options?: UserOperationOptions
|
||||||
swap_operation_id_CustomCheck?: (v: string) => boolean
|
quote_Options?: InvoiceSwapQuoteOptions
|
||||||
tx_id_CustomCheck?: (v: string) => boolean
|
|
||||||
}
|
}
|
||||||
export const InvoiceSwapOperationValidate = (o?: InvoiceSwapOperation, opts: InvoiceSwapOperationOptions = {}, path: string = 'InvoiceSwapOperation::root.'): Error | null => {
|
export const InvoiceSwapOperationValidate = (o?: InvoiceSwapOperation, opts: InvoiceSwapOperationOptions = {}, path: string = 'InvoiceSwapOperation::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')
|
||||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if ((o.completed_at_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('completed_at_unix')) && typeof o.completed_at_unix !== 'number') return new Error(`${path}.completed_at_unix: is not a number`)
|
||||||
|
if (opts.completed_at_unix_CustomCheck && !opts.completed_at_unix_CustomCheck(o.completed_at_unix)) return new Error(`${path}.completed_at_unix: custom check failed`)
|
||||||
|
|
||||||
if ((o.failure_reason || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('failure_reason')) && typeof o.failure_reason !== 'string') return new Error(`${path}.failure_reason: is not a string`)
|
if ((o.failure_reason || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('failure_reason')) && typeof o.failure_reason !== 'string') return new Error(`${path}.failure_reason: is not a string`)
|
||||||
if (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`)
|
if (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.invoice_paid !== 'string') return new Error(`${path}.invoice_paid: is not a string`)
|
|
||||||
if (opts.invoice_paid_CustomCheck && !opts.invoice_paid_CustomCheck(o.invoice_paid)) return new Error(`${path}.invoice_paid: custom check failed`)
|
|
||||||
|
|
||||||
if (typeof o.operation_payment === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('operation_payment')) {
|
if (typeof o.operation_payment === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('operation_payment')) {
|
||||||
const operation_paymentErr = UserOperationValidate(o.operation_payment, opts.operation_payment_Options, `${path}.operation_payment`)
|
const operation_paymentErr = UserOperationValidate(o.operation_payment, opts.operation_payment_Options, `${path}.operation_payment`)
|
||||||
if (operation_paymentErr !== null) return operation_paymentErr
|
if (operation_paymentErr !== null) return operation_paymentErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`)
|
const quoteErr = InvoiceSwapQuoteValidate(o.quote, opts.quote_Options, `${path}.quote`)
|
||||||
if (opts.swap_operation_id_CustomCheck && !opts.swap_operation_id_CustomCheck(o.swap_operation_id)) return new Error(`${path}.swap_operation_id: custom check failed`)
|
if (quoteErr !== null) return quoteErr
|
||||||
|
|
||||||
if (typeof o.tx_id !== 'string') return new Error(`${path}.tx_id: is not a string`)
|
|
||||||
if (opts.tx_id_CustomCheck && !opts.tx_id_CustomCheck(o.tx_id)) return new Error(`${path}.tx_id: custom check failed`)
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
@ -2167,8 +2163,10 @@ export const InvoiceSwapOperationValidate = (o?: InvoiceSwapOperation, opts: Inv
|
||||||
export type InvoiceSwapQuote = {
|
export type InvoiceSwapQuote = {
|
||||||
address: string
|
address: string
|
||||||
chain_fee_sats: number
|
chain_fee_sats: number
|
||||||
|
expires_at_block_height: number
|
||||||
invoice: string
|
invoice: string
|
||||||
invoice_amount_sats: number
|
invoice_amount_sats: number
|
||||||
|
paid_at_unix: number
|
||||||
service_fee_sats: number
|
service_fee_sats: number
|
||||||
service_url: string
|
service_url: string
|
||||||
swap_fee_sats: number
|
swap_fee_sats: number
|
||||||
|
|
@ -2181,8 +2179,10 @@ export type InvoiceSwapQuoteOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: []
|
checkOptionalsAreSet?: []
|
||||||
address_CustomCheck?: (v: string) => boolean
|
address_CustomCheck?: (v: string) => boolean
|
||||||
chain_fee_sats_CustomCheck?: (v: number) => boolean
|
chain_fee_sats_CustomCheck?: (v: number) => boolean
|
||||||
|
expires_at_block_height_CustomCheck?: (v: number) => boolean
|
||||||
invoice_CustomCheck?: (v: string) => boolean
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
invoice_amount_sats_CustomCheck?: (v: number) => boolean
|
invoice_amount_sats_CustomCheck?: (v: number) => boolean
|
||||||
|
paid_at_unix_CustomCheck?: (v: number) => boolean
|
||||||
service_fee_sats_CustomCheck?: (v: number) => boolean
|
service_fee_sats_CustomCheck?: (v: number) => boolean
|
||||||
service_url_CustomCheck?: (v: string) => boolean
|
service_url_CustomCheck?: (v: string) => boolean
|
||||||
swap_fee_sats_CustomCheck?: (v: number) => boolean
|
swap_fee_sats_CustomCheck?: (v: number) => boolean
|
||||||
|
|
@ -2200,12 +2200,18 @@ export const InvoiceSwapQuoteValidate = (o?: InvoiceSwapQuote, opts: InvoiceSwap
|
||||||
if (typeof o.chain_fee_sats !== 'number') return new Error(`${path}.chain_fee_sats: is not a number`)
|
if (typeof o.chain_fee_sats !== 'number') return new Error(`${path}.chain_fee_sats: is not a number`)
|
||||||
if (opts.chain_fee_sats_CustomCheck && !opts.chain_fee_sats_CustomCheck(o.chain_fee_sats)) return new Error(`${path}.chain_fee_sats: custom check failed`)
|
if (opts.chain_fee_sats_CustomCheck && !opts.chain_fee_sats_CustomCheck(o.chain_fee_sats)) return new Error(`${path}.chain_fee_sats: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.expires_at_block_height !== 'number') return new Error(`${path}.expires_at_block_height: is not a number`)
|
||||||
|
if (opts.expires_at_block_height_CustomCheck && !opts.expires_at_block_height_CustomCheck(o.expires_at_block_height)) return new Error(`${path}.expires_at_block_height: custom check failed`)
|
||||||
|
|
||||||
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`)
|
||||||
|
|
||||||
if (typeof o.invoice_amount_sats !== 'number') return new Error(`${path}.invoice_amount_sats: is not a number`)
|
if (typeof o.invoice_amount_sats !== 'number') return new Error(`${path}.invoice_amount_sats: is not a number`)
|
||||||
if (opts.invoice_amount_sats_CustomCheck && !opts.invoice_amount_sats_CustomCheck(o.invoice_amount_sats)) return new Error(`${path}.invoice_amount_sats: custom check failed`)
|
if (opts.invoice_amount_sats_CustomCheck && !opts.invoice_amount_sats_CustomCheck(o.invoice_amount_sats)) return new Error(`${path}.invoice_amount_sats: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.paid_at_unix !== 'number') return new Error(`${path}.paid_at_unix: is not a number`)
|
||||||
|
if (opts.paid_at_unix_CustomCheck && !opts.paid_at_unix_CustomCheck(o.paid_at_unix)) return new Error(`${path}.paid_at_unix: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.service_fee_sats !== 'number') return new Error(`${path}.service_fee_sats: is not a number`)
|
if (typeof o.service_fee_sats !== 'number') return new Error(`${path}.service_fee_sats: is not a number`)
|
||||||
if (opts.service_fee_sats_CustomCheck && !opts.service_fee_sats_CustomCheck(o.service_fee_sats)) return new Error(`${path}.service_fee_sats: custom check failed`)
|
if (opts.service_fee_sats_CustomCheck && !opts.service_fee_sats_CustomCheck(o.service_fee_sats)) return new Error(`${path}.service_fee_sats: custom check failed`)
|
||||||
|
|
||||||
|
|
@ -2269,14 +2275,13 @@ export const InvoiceSwapRequestValidate = (o?: InvoiceSwapRequest, opts: Invoice
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InvoiceSwapsList = {
|
export type InvoiceSwapsList = {
|
||||||
quotes: InvoiceSwapQuote[]
|
current_block_height: number
|
||||||
swaps: InvoiceSwapOperation[]
|
swaps: InvoiceSwapOperation[]
|
||||||
}
|
}
|
||||||
export const InvoiceSwapsListOptionalFields: [] = []
|
export const InvoiceSwapsListOptionalFields: [] = []
|
||||||
export type InvoiceSwapsListOptions = OptionsBaseMessage & {
|
export type InvoiceSwapsListOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: []
|
checkOptionalsAreSet?: []
|
||||||
quotes_ItemOptions?: InvoiceSwapQuoteOptions
|
current_block_height_CustomCheck?: (v: number) => boolean
|
||||||
quotes_CustomCheck?: (v: InvoiceSwapQuote[]) => boolean
|
|
||||||
swaps_ItemOptions?: InvoiceSwapOperationOptions
|
swaps_ItemOptions?: InvoiceSwapOperationOptions
|
||||||
swaps_CustomCheck?: (v: InvoiceSwapOperation[]) => boolean
|
swaps_CustomCheck?: (v: InvoiceSwapOperation[]) => boolean
|
||||||
}
|
}
|
||||||
|
|
@ -2284,12 +2289,8 @@ export const InvoiceSwapsListValidate = (o?: InvoiceSwapsList, opts: InvoiceSwap
|
||||||
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')
|
||||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
if (!Array.isArray(o.quotes)) return new Error(`${path}.quotes: is not an array`)
|
if (typeof o.current_block_height !== 'number') return new Error(`${path}.current_block_height: is not a number`)
|
||||||
for (let index = 0; index < o.quotes.length; index++) {
|
if (opts.current_block_height_CustomCheck && !opts.current_block_height_CustomCheck(o.current_block_height)) return new Error(`${path}.current_block_height: custom check failed`)
|
||||||
const quotesErr = InvoiceSwapQuoteValidate(o.quotes[index], opts.quotes_ItemOptions, `${path}.quotes[${index}]`)
|
|
||||||
if (quotesErr !== null) return quotesErr
|
|
||||||
}
|
|
||||||
if (opts.quotes_CustomCheck && !opts.quotes_CustomCheck(o.quotes)) return new Error(`${path}.quotes: custom check failed`)
|
|
||||||
|
|
||||||
if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`)
|
if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`)
|
||||||
for (let index = 0; index < o.swaps.length; index++) {
|
for (let index = 0; index < o.swaps.length; index++) {
|
||||||
|
|
|
||||||
|
|
@ -848,6 +848,8 @@ message InvoiceSwapQuote {
|
||||||
string service_url = 8;
|
string service_url = 8;
|
||||||
int64 swap_fee_sats = 9;
|
int64 swap_fee_sats = 9;
|
||||||
string tx_id = 10;
|
string tx_id = 10;
|
||||||
|
int64 paid_at_unix = 11;
|
||||||
|
int64 expires_at_block_height = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InvoiceSwapQuoteList {
|
message InvoiceSwapQuoteList {
|
||||||
|
|
@ -855,16 +857,15 @@ message InvoiceSwapQuoteList {
|
||||||
}
|
}
|
||||||
|
|
||||||
message InvoiceSwapOperation {
|
message InvoiceSwapOperation {
|
||||||
string swap_operation_id = 1;
|
InvoiceSwapQuote quote = 1;
|
||||||
optional UserOperation operation_payment = 2;
|
optional UserOperation operation_payment = 2;
|
||||||
optional string failure_reason = 3;
|
optional string failure_reason = 3;
|
||||||
string invoice_paid = 4;
|
optional int64 completed_at_unix = 6;
|
||||||
string tx_id = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message InvoiceSwapsList {
|
message InvoiceSwapsList {
|
||||||
repeated InvoiceSwapOperation swaps = 1;
|
repeated InvoiceSwapOperation swaps = 1;
|
||||||
repeated InvoiceSwapQuote quotes = 2;
|
int64 current_block_height = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RefundAdminInvoiceSwapRequest {
|
message RefundAdminInvoiceSwapRequest {
|
||||||
|
|
|
||||||
|
|
@ -71,19 +71,7 @@ export class Swaps {
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
ListInvoiceSwaps = async (appUserId: string): Promise<Types.InvoiceSwapsList> => {
|
private mapInvoiceSwapQuote = (s: InvoiceSwap): Types.InvoiceSwapQuote => {
|
||||||
const completedSwaps = await this.storage.paymentStorage.ListCompletedInvoiceSwaps(appUserId)
|
|
||||||
const pendingSwaps = await this.storage.paymentStorage.ListPendingInvoiceSwaps(appUserId)
|
|
||||||
return {
|
|
||||||
swaps: completedSwaps.map(s => {
|
|
||||||
return {
|
|
||||||
invoice_paid: s.invoice,
|
|
||||||
swap_operation_id: s.swap_operation_id,
|
|
||||||
failure_reason: s.failure_reason,
|
|
||||||
tx_id: s.tx_id,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
quotes: pendingSwaps.map(s => {
|
|
||||||
return {
|
return {
|
||||||
swap_operation_id: s.swap_operation_id,
|
swap_operation_id: s.swap_operation_id,
|
||||||
invoice: s.invoice,
|
invoice: s.invoice,
|
||||||
|
|
@ -95,8 +83,25 @@ export class Swaps {
|
||||||
service_url: s.service_url,
|
service_url: s.service_url,
|
||||||
swap_fee_sats: s.swap_fee_sats,
|
swap_fee_sats: s.swap_fee_sats,
|
||||||
tx_id: s.tx_id,
|
tx_id: s.tx_id,
|
||||||
|
paid_at_unix: s.paid_at_unix,
|
||||||
|
expires_at_block_height: s.timeout_block_height,
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
ListInvoiceSwaps = async (appUserId: string): Promise<Types.InvoiceSwapsList> => {
|
||||||
|
const info = await this.lnd.GetInfo()
|
||||||
|
const currentBlockHeight = info.blockHeight
|
||||||
|
const completedSwaps = await this.storage.paymentStorage.ListCompletedInvoiceSwaps(appUserId)
|
||||||
|
const pendingSwaps = await this.storage.paymentStorage.ListPendingInvoiceSwaps(appUserId)
|
||||||
|
const quotes: Types.InvoiceSwapOperation[] = pendingSwaps.map(s => ({ quote: this.mapInvoiceSwapQuote(s) }))
|
||||||
|
const operations: Types.InvoiceSwapOperation[] = completedSwaps.map(s => ({
|
||||||
|
quote: this.mapInvoiceSwapQuote(s),
|
||||||
|
failure_reason: s.failure_reason,
|
||||||
|
completed_at_unix: s.completed_at_unix || 1,
|
||||||
|
}))
|
||||||
|
return {
|
||||||
|
current_block_height: currentBlockHeight,
|
||||||
|
swaps: operations.concat(quotes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,6 +266,8 @@ export class Swaps {
|
||||||
service_url: swapper.getHttpUrl(),
|
service_url: swapper.getHttpUrl(),
|
||||||
swap_fee_sats: fee,
|
swap_fee_sats: fee,
|
||||||
tx_id: newSwap.tx_id,
|
tx_id: newSwap.tx_id,
|
||||||
|
paid_at_unix: newSwap.paid_at_unix,
|
||||||
|
expires_at_block_height: newSwap.timeout_block_height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -280,14 +280,16 @@ export class AdminManager {
|
||||||
|
|
||||||
// Fetch the full transaction hex for potential refunds
|
// Fetch the full transaction hex for potential refunds
|
||||||
let lockupTxHex: string | undefined
|
let lockupTxHex: string | undefined
|
||||||
|
let chainFeeSats = 0
|
||||||
try {
|
try {
|
||||||
const txDetails = await this.lnd.GetTx(tx.txid)
|
const txDetails = await this.lnd.GetTx(tx.txid)
|
||||||
|
chainFeeSats = Number(txDetails.totalFees)
|
||||||
lockupTxHex = txDetails.rawTxHex
|
lockupTxHex = txDetails.rawTxHex
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.log("Warning: Could not fetch transaction hex for refund purposes:", err.message)
|
this.log("Warning: Could not fetch transaction hex for refund purposes:", err.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.storage.paymentStorage.SetInvoiceSwapTxId(req.swap_operation_id, tx.txid, lockupTxHex)
|
await this.storage.paymentStorage.SetInvoiceSwapTxId(req.swap_operation_id, tx.txid, chainFeeSats, lockupTxHex)
|
||||||
this.log("saved admin swap txid", { swapOpId: req.swap_operation_id, txId: tx.txid })
|
this.log("saved admin swap txid", { swapOpId: req.swap_operation_id, txId: tx.txid })
|
||||||
res(tx.txid)
|
res(tx.txid)
|
||||||
return { txId: tx.txid }
|
return { txId: tx.txid }
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,12 @@ export class InvoiceSwap {
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
used: boolean
|
used: boolean
|
||||||
|
|
||||||
|
@Column({ default: 0 })
|
||||||
|
completed_at_unix: number
|
||||||
|
|
||||||
|
@Column({ default: 0 })
|
||||||
|
paid_at_unix: number
|
||||||
|
|
||||||
@Column({ default: "" })
|
@Column({ default: "" })
|
||||||
preimage: string
|
preimage: string
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class SwapTimestamps1771347307798 implements MigrationInterface {
|
||||||
|
name = 'SwapTimestamps1771347307798'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_invoice_swap" ("swap_operation_id" varchar PRIMARY KEY NOT NULL, "app_user_id" varchar NOT NULL, "swap_quote_id" varchar NOT NULL, "swap_tree" varchar NOT NULL, "claim_public_key" varchar NOT NULL, "payment_hash" varchar NOT NULL, "timeout_block_height" integer NOT NULL, "invoice" varchar NOT NULL, "invoice_amount" integer NOT NULL, "transaction_amount" integer NOT NULL, "swap_fee_sats" integer NOT NULL, "chain_fee_sats" integer NOT NULL, "ephemeral_public_key" varchar NOT NULL, "address" varchar NOT NULL, "ephemeral_private_key" varchar NOT NULL, "used" boolean NOT NULL DEFAULT (0), "preimage" varchar NOT NULL DEFAULT (''), "failure_reason" varchar NOT NULL DEFAULT (''), "tx_id" varchar NOT NULL DEFAULT (''), "service_url" varchar NOT NULL DEFAULT (''), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "lockup_tx_hex" text NOT NULL DEFAULT (''), "completed_at_unix" integer NOT NULL DEFAULT (0), "paid_at_unix" integer NOT NULL DEFAULT (0))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_invoice_swap"("swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "claim_public_key", "payment_hash", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "ephemeral_public_key", "address", "ephemeral_private_key", "used", "preimage", "failure_reason", "tx_id", "service_url", "created_at", "updated_at", "lockup_tx_hex") SELECT "swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "claim_public_key", "payment_hash", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "ephemeral_public_key", "address", "ephemeral_private_key", "used", "preimage", "failure_reason", "tx_id", "service_url", "created_at", "updated_at", "lockup_tx_hex" FROM "invoice_swap"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "invoice_swap"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_invoice_swap" RENAME TO "invoice_swap"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "invoice_swap" RENAME TO "temporary_invoice_swap"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "invoice_swap" ("swap_operation_id" varchar PRIMARY KEY NOT NULL, "app_user_id" varchar NOT NULL, "swap_quote_id" varchar NOT NULL, "swap_tree" varchar NOT NULL, "claim_public_key" varchar NOT NULL, "payment_hash" varchar NOT NULL, "timeout_block_height" integer NOT NULL, "invoice" varchar NOT NULL, "invoice_amount" integer NOT NULL, "transaction_amount" integer NOT NULL, "swap_fee_sats" integer NOT NULL, "chain_fee_sats" integer NOT NULL, "ephemeral_public_key" varchar NOT NULL, "address" varchar NOT NULL, "ephemeral_private_key" varchar NOT NULL, "used" boolean NOT NULL DEFAULT (0), "preimage" varchar NOT NULL DEFAULT (''), "failure_reason" varchar NOT NULL DEFAULT (''), "tx_id" varchar NOT NULL DEFAULT (''), "service_url" varchar NOT NULL DEFAULT (''), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "lockup_tx_hex" text NOT NULL DEFAULT (''))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "invoice_swap"("swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "claim_public_key", "payment_hash", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "ephemeral_public_key", "address", "ephemeral_private_key", "used", "preimage", "failure_reason", "tx_id", "service_url", "created_at", "updated_at", "lockup_tx_hex") SELECT "swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "claim_public_key", "payment_hash", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "ephemeral_public_key", "address", "ephemeral_private_key", "used", "preimage", "failure_reason", "tx_id", "service_url", "created_at", "updated_at", "lockup_tx_hex" FROM "temporary_invoice_swap"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_invoice_swap"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -34,13 +34,15 @@ import { TrackedProviderHeight1766504040000 } from './1766504040000-tracked_prov
|
||||||
import { SwapsServiceUrl1768413055036 } from './1768413055036-swaps_service_url.js'
|
import { SwapsServiceUrl1768413055036 } from './1768413055036-swaps_service_url.js'
|
||||||
import { InvoiceSwaps1769529793283 } from './1769529793283-invoice_swaps.js'
|
import { InvoiceSwaps1769529793283 } from './1769529793283-invoice_swaps.js'
|
||||||
import { InvoiceSwapsFixes1769805357459 } from './1769805357459-invoice_swaps_fixes.js'
|
import { InvoiceSwapsFixes1769805357459 } from './1769805357459-invoice_swaps_fixes.js'
|
||||||
|
import { SwapTimestamps1771347307798 } from './1771347307798-swap_timestamps.js'
|
||||||
|
|
||||||
export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189,
|
export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189,
|
||||||
TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264,
|
TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264,
|
||||||
DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513,
|
DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513,
|
||||||
InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175,
|
InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175,
|
||||||
UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098,
|
UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098,
|
||||||
TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036, InvoiceSwaps1769529793283, InvoiceSwapsFixes1769805357459]
|
TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036,
|
||||||
|
InvoiceSwaps1769529793283, InvoiceSwapsFixes1769805357459, SwapTimestamps1771347307798]
|
||||||
|
|
||||||
export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411]
|
export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411]
|
||||||
/* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {
|
/* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {
|
||||||
|
|
|
||||||
|
|
@ -530,8 +530,10 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async FinalizeInvoiceSwap(swapOperationId: string, txId?: string) {
|
async FinalizeInvoiceSwap(swapOperationId: string, txId?: string) {
|
||||||
|
const now = Math.floor(Date.now() / 1000)
|
||||||
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
|
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
|
||||||
used: true,
|
used: true,
|
||||||
|
completed_at_unix: now,
|
||||||
}, txId)
|
}, txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -539,9 +541,12 @@ export default class {
|
||||||
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, update, txId)
|
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, update, txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
async SetInvoiceSwapTxId(swapOperationId: string, chainTxId: string, lockupTxHex?: string, txId?: string) {
|
async SetInvoiceSwapTxId(swapOperationId: string, chainTxId: string, chainFeeSats: number, lockupTxHex?: string, txId?: string) {
|
||||||
|
const now = Math.floor(Date.now() / 1000)
|
||||||
const update: Partial<InvoiceSwap> = {
|
const update: Partial<InvoiceSwap> = {
|
||||||
tx_id: chainTxId,
|
tx_id: chainTxId,
|
||||||
|
paid_at_unix: now,
|
||||||
|
chain_fee_sats: chainFeeSats,
|
||||||
}
|
}
|
||||||
if (lockupTxHex) {
|
if (lockupTxHex) {
|
||||||
update.lockup_tx_hex = lockupTxHex
|
update.lockup_tx_hex = lockupTxHex
|
||||||
|
|
@ -550,9 +555,11 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async FailInvoiceSwap(swapOperationId: string, failureReason: string, txId?: string) {
|
async FailInvoiceSwap(swapOperationId: string, failureReason: string, txId?: string) {
|
||||||
|
const now = Math.floor(Date.now() / 1000)
|
||||||
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
|
return this.dbs.Update<InvoiceSwap>('InvoiceSwap', { swap_operation_id: swapOperationId }, {
|
||||||
used: true,
|
used: true,
|
||||||
failure_reason: failureReason,
|
failure_reason: failureReason,
|
||||||
|
completed_at_unix: now,
|
||||||
}, txId)
|
}, txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue