diff --git a/datasource.js b/datasource.js index 4badca25..dfae53bf 100644 --- a/datasource.js +++ b/datasource.js @@ -1,14 +1,3 @@ -/** - * 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 { User } from "./build/src/services/storage/entity/User.js" import { UserReceivingInvoice } from "./build/src/services/storage/entity/UserReceivingInvoice.js" @@ -33,13 +22,11 @@ import { AppUserDevice } from "./build/src/services/storage/entity/AppUserDevice import { UserAccess } from "./build/src/services/storage/entity/UserAccess.js" import { AdminSettings } from "./build/src/services/storage/entity/AdminSettings.js" import { TransactionSwap } from "./build/src/services/storage/entity/TransactionSwap.js" -import { InvoiceSwap } from "./build/src/services/storage/entity/InvoiceSwap.js" import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js' import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js' -import { LiquidityProvider1719335699480 } from './build/src/services/storage/migrations/1719335699480-liquidity_provider.js' import { LndNodeInfo1720187506189 } from './build/src/services/storage/migrations/1720187506189-lnd_node_info.js' -import { TrackedProvider1720814323679 } from './build/src/services/storage/migrations/1720814323679-tracked_provider.js' +import { LiquidityProvider1719335699480 } from './build/src/services/storage/migrations/1719335699480-liquidity_provider.js' import { CreateInviteTokenTable1721751414878 } from './build/src/services/storage/migrations/1721751414878-create_invite_token_table.js' import { PaymentIndex1721760297610 } from './build/src/services/storage/migrations/1721760297610-payment_index.js' import { DebitAccess1726496225078 } from './build/src/services/storage/migrations/1726496225078-debit_access.js' @@ -48,7 +35,6 @@ import { DebitToPub1727105758354 } from './build/src/services/storage/migrations import { UserCbUrl1727112281043 } from './build/src/services/storage/migrations/1727112281043-user_cb_url.js' import { UserOffer1733502626042 } from './build/src/services/storage/migrations/1733502626042-user_offer.js' import { ManagementGrant1751307732346 } from './build/src/services/storage/migrations/1751307732346-management_grant.js' -import { ManagementGrantBanned1751989251513 } from './build/src/services/storage/migrations/1751989251513-management_grant_banned.js' import { InvoiceCallbackUrls1752425992291 } from './build/src/services/storage/migrations/1752425992291-invoice_callback_urls.js' import { OldSomethingLeftover1753106599604 } from './build/src/services/storage/migrations/1753106599604-old_something_leftover.js' import { UserReceivingInvoiceIdx1753109184611 } from './build/src/services/storage/migrations/1753109184611-user_receiving_invoice_idx.js' @@ -61,32 +47,20 @@ import { TxSwap1762890527098 } from './build/src/services/storage/migrations/176 import { TxSwapAddress1764779178945 } from './build/src/services/storage/migrations/1764779178945-tx_swap_address.js' import { ClinkRequester1765497600000 } from './build/src/services/storage/migrations/1765497600000-clink_requester.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 { InvoiceSwaps1769529793283 } from './build/src/services/storage/migrations/1769529793283-invoice_swaps.js' -import { InvoiceSwapsFixes1769805357459 } from './build/src/services/storage/migrations/1769805357459-invoice_swaps_fixes.js' -import { ApplicationUserTopicId1770038768784 } from './build/src/services/storage/migrations/1770038768784-application_user_topic_id.js' -import { SwapTimestamps1771347307798 } from './build/src/services/storage/migrations/1771347307798-swap_timestamps.js' - - - export default new DataSource({ type: "better-sqlite3", database: "db.sqlite", // logging: true, - migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, - TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, - DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513, - InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175, - UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098, - TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036, - InvoiceSwaps1769529793283, InvoiceSwapsFixes1769805357459, ApplicationUserTopicId1770038768784, SwapTimestamps1771347307798 - ], - + migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, + PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043, + UserOffer1733502626042, ManagementGrant1751307732346, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, + AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098, + TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000], entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, 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], // synchronize: true, }) -//npx typeorm migration:generate ./src/services/storage/migrations/tx_swap_timestamps -d ./datasource.js \ No newline at end of file +//npx typeorm migration:generate ./src/services/storage/migrations/swaps_service_url -d ./datasource.js \ No newline at end of file diff --git a/metricsDatasource.js b/metricsDatasource.js index aaf5ddbc..226b9dac 100644 --- a/metricsDatasource.js +++ b/metricsDatasource.js @@ -1,14 +1,3 @@ -/** - * 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 { BalanceEvent } from "./build/src/services/storage/entity/BalanceEvent.js" import { ChannelBalanceEvent } from "./build/src/services/storage/entity/ChannelsBalanceEvent.js" @@ -19,16 +8,12 @@ import { LndMetrics1703170330183 } from './build/src/services/storage/migrations import { ChannelRouting1709316653538 } from './build/src/services/storage/migrations/1709316653538-channel_routing.js' import { HtlcCount1724266887195 } from './build/src/services/storage/migrations/1724266887195-htlc_count.js' import { BalanceEvents1724860966825 } from './build/src/services/storage/migrations/1724860966825-balance_events.js' -import { RootOps1732566440447 } from './build/src/services/storage/migrations/1732566440447-root_ops.js' -import { RootOpsTime1745428134124 } from './build/src/services/storage/migrations/1745428134124-root_ops_time.js' -import { ChannelEvents1750777346411 } from './build/src/services/storage/migrations/1750777346411-channel_events.js' -import { RootOpPending1771524665409 } from './build/src/services/storage/migrations/1771524665409-root_op_pending.js' + export default new DataSource({ type: "better-sqlite3", database: "metrics.sqlite", entities: [BalanceEvent, ChannelBalanceEvent, ChannelRouting, RootOperation, ChannelEvent], - migrations: [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, - RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411, RootOpPending1771524665409] + migrations: [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825] }); -//npx typeorm migration:generate ./src/services/storage/migrations/root_op_pending -d ./metricsDatasource.js \ No newline at end of file +//npx typeorm migration:generate ./src/services/storage/migrations/channel_events -d ./metricsDatasource.js \ No newline at end of file diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index d42fc9ac..99023c69 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -58,11 +58,6 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - This methods has an __empty__ __response__ body -- BumpTx - - auth type: __Admin__ - - input: [BumpTx](#BumpTx) - - This methods has an __empty__ __response__ body - - CloseChannel - auth type: __Admin__ - input: [CloseChannelRequest](#CloseChannelRequest) @@ -98,11 +93,6 @@ The nostr server will send back a message response, and inside the body there wi - input: [MessagingToken](#MessagingToken) - This methods has an __empty__ __response__ body -- GetAdminInvoiceSwapQuotes - - auth type: __Admin__ - - input: [InvoiceSwapRequest](#InvoiceSwapRequest) - - output: [InvoiceSwapQuoteList](#InvoiceSwapQuoteList) - - GetAdminTransactionSwapQuotes - auth type: __Admin__ - input: [TransactionSwapRequest](#TransactionSwapRequest) @@ -113,11 +103,6 @@ The nostr server will send back a message response, and inside the body there wi - input: [AppsMetricsRequest](#AppsMetricsRequest) - output: [AppsMetrics](#AppsMetrics) -- GetAssetsAndLiabilities - - auth type: __Admin__ - - input: [AssetsAndLiabilitiesReq](#AssetsAndLiabilitiesReq) - - output: [AssetsAndLiabilities](#AssetsAndLiabilities) - - GetBundleMetrics - auth type: __Metrics__ - input: [LatestBundleMetricReq](#LatestBundleMetricReq) @@ -258,25 +243,20 @@ The nostr server will send back a message response, and inside the body there wi - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) - This methods has an __empty__ __response__ body -- ListAdminInvoiceSwaps +- ListAdminSwaps - auth type: __Admin__ - This methods has an __empty__ __request__ body - - output: [InvoiceSwapsList](#InvoiceSwapsList) - -- ListAdminTxSwaps - - auth type: __Admin__ - - This methods has an __empty__ __request__ body - - output: [TxSwapsList](#TxSwapsList) + - output: [SwapsList](#SwapsList) - ListChannels - auth type: __Admin__ - This methods has an __empty__ __request__ body - output: [LndChannels](#LndChannels) -- ListTxSwaps +- ListSwaps - auth type: __User__ - This methods has an __empty__ __request__ body - - output: [TxSwapsList](#TxSwapsList) + - output: [SwapsList](#SwapsList) - LndGetInfo - auth type: __Admin__ @@ -310,15 +290,10 @@ The nostr server will send back a message response, and inside the body there wi - input: [PayAddressRequest](#PayAddressRequest) - output: [PayAddressResponse](#PayAddressResponse) -- PayAdminInvoiceSwap - - auth type: __Admin__ - - input: [PayAdminInvoiceSwapRequest](#PayAdminInvoiceSwapRequest) - - output: [AdminInvoiceSwapResponse](#AdminInvoiceSwapResponse) - - PayAdminTransactionSwap - auth type: __Admin__ - input: [PayAdminTransactionSwapRequest](#PayAdminTransactionSwapRequest) - - output: [AdminTxSwapResponse](#AdminTxSwapResponse) + - output: [AdminSwapResponse](#AdminSwapResponse) - PayInvoice - auth type: __User__ @@ -330,11 +305,6 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - This methods has an __empty__ __response__ body -- RefundAdminInvoiceSwap - - auth type: __Admin__ - - input: [RefundAdminInvoiceSwapRequest](#RefundAdminInvoiceSwapRequest) - - output: [AdminInvoiceSwapResponse](#AdminInvoiceSwapResponse) - - ResetDebit - auth type: __User__ - input: [DebitOperation](#DebitOperation) @@ -514,13 +484,6 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - This methods has an __empty__ __response__ body -- BumpTx - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/tx/bump__ - - input: [BumpTx](#BumpTx) - - This methods has an __empty__ __response__ body - - CloseChannel - auth type: __Admin__ - http method: __post__ @@ -577,13 +540,6 @@ The nostr server will send back a message response, and inside the body there wi - input: [MessagingToken](#MessagingToken) - This methods has an __empty__ __response__ body -- GetAdminInvoiceSwapQuotes - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/swap/invoice/quote__ - - input: [InvoiceSwapRequest](#InvoiceSwapRequest) - - output: [InvoiceSwapQuoteList](#InvoiceSwapQuoteList) - - GetAdminTransactionSwapQuotes - auth type: __Admin__ - http method: __post__ @@ -619,13 +575,6 @@ The nostr server will send back a message response, and inside the body there wi - input: [AppsMetricsRequest](#AppsMetricsRequest) - output: [AppsMetrics](#AppsMetrics) -- GetAssetsAndLiabilities - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/assets/liabilities__ - - input: [AssetsAndLiabilitiesReq](#AssetsAndLiabilitiesReq) - - output: [AssetsAndLiabilities](#AssetsAndLiabilities) - - GetBundleMetrics - auth type: __Metrics__ - http method: __post__ @@ -794,7 +743,7 @@ The nostr server will send back a message response, and inside the body there wi - GetTransactionSwapQuotes - auth type: __User__ - http method: __post__ - - http route: __/api/user/swap/transaction/quote__ + - http route: __/api/user/swap/quote__ - input: [TransactionSwapRequest](#TransactionSwapRequest) - output: [TransactionSwapQuoteList](#TransactionSwapQuoteList) @@ -885,19 +834,12 @@ The nostr server will send back a message response, and inside the body there wi - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) - This methods has an __empty__ __response__ body -- ListAdminInvoiceSwaps +- ListAdminSwaps - auth type: __Admin__ - http method: __post__ - - http route: __/api/admin/swap/invoice/list__ + - http route: __/api/admin/swap/list__ - This methods has an __empty__ __request__ body - - output: [InvoiceSwapsList](#InvoiceSwapsList) - -- ListAdminTxSwaps - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/swap/transaction/list__ - - This methods has an __empty__ __request__ body - - output: [TxSwapsList](#TxSwapsList) + - output: [SwapsList](#SwapsList) - ListChannels - auth type: __Admin__ @@ -906,12 +848,12 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - output: [LndChannels](#LndChannels) -- ListTxSwaps +- ListSwaps - auth type: __User__ - http method: __post__ - - http route: __/api/user/swap/transaction/list__ + - http route: __/api/user/swap/list__ - This methods has an __empty__ __request__ body - - output: [TxSwapsList](#TxSwapsList) + - output: [SwapsList](#SwapsList) - LndGetInfo - auth type: __Admin__ @@ -957,19 +899,12 @@ The nostr server will send back a message response, and inside the body there wi - input: [PayAddressRequest](#PayAddressRequest) - output: [PayAddressResponse](#PayAddressResponse) -- PayAdminInvoiceSwap - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/swap/invoice/pay__ - - input: [PayAdminInvoiceSwapRequest](#PayAdminInvoiceSwapRequest) - - output: [AdminInvoiceSwapResponse](#AdminInvoiceSwapResponse) - - PayAdminTransactionSwap - auth type: __Admin__ - http method: __post__ - http route: __/api/admin/swap/transaction/pay__ - input: [PayAdminTransactionSwapRequest](#PayAdminTransactionSwapRequest) - - output: [AdminTxSwapResponse](#AdminTxSwapResponse) + - output: [AdminSwapResponse](#AdminSwapResponse) - PayAppUserInvoice - auth type: __App__ @@ -992,13 +927,6 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - This methods has an __empty__ __response__ body -- RefundAdminInvoiceSwap - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/swap/invoice/refund__ - - input: [RefundAdminInvoiceSwapRequest](#RefundAdminInvoiceSwapRequest) - - output: [AdminInvoiceSwapResponse](#AdminInvoiceSwapResponse) - - RequestNPubLinkingToken - auth type: __App__ - http method: __post__ @@ -1170,10 +1098,7 @@ The nostr server will send back a message response, and inside the body there wi - __name__: _string_ - __price_sats__: _number_ -### AdminInvoiceSwapResponse - - __tx_id__: _string_ - -### AdminTxSwapResponse +### AdminSwapResponse - __network_fee__: _number_ - __tx_id__: _string_ @@ -1210,21 +1135,6 @@ The nostr server will send back a message response, and inside the body there wi - __include_operations__: _boolean_ *this field is optional - __to_unix__: _number_ *this field is optional -### AssetOperation - - __amount__: _number_ - - __tracked__: _[TrackedOperation](#TrackedOperation)_ *this field is optional - - __ts__: _number_ - -### AssetsAndLiabilities - - __liquidity_providers__: ARRAY of: _[LiquidityAssetProvider](#LiquidityAssetProvider)_ - - __lnds__: ARRAY of: _[LndAssetProvider](#LndAssetProvider)_ - - __users_balance__: _number_ - -### AssetsAndLiabilitiesReq - - __limit_invoices__: _number_ *this field is optional - - __limit_payments__: _number_ *this field is optional - - __limit_providers__: _number_ *this field is optional - ### AuthApp - __app__: _[Application](#Application)_ - __auth_token__: _string_ @@ -1253,11 +1163,6 @@ The nostr server will send back a message response, and inside the body there wi - __nextRelay__: _string_ *this field is optional - __type__: _string_ -### BumpTx - - __output_index__: _number_ - - __sat_per_vbyte__: _number_ - - __txid__: _string_ - ### BundleData - __available_chunks__: ARRAY of: _number_ - __base_64_data__: ARRAY of: _string_ @@ -1426,36 +1331,6 @@ The nostr server will send back a message response, and inside the body there wi - __token__: _string_ - __url__: _string_ -### InvoiceSwapOperation - - __completed_at_unix__: _number_ *this field is optional - - __failure_reason__: _string_ *this field is optional - - __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional - - __quote__: _[InvoiceSwapQuote](#InvoiceSwapQuote)_ - -### InvoiceSwapQuote - - __address__: _string_ - - __chain_fee_sats__: _number_ - - __expires_at_block_height__: _number_ - - __invoice__: _string_ - - __invoice_amount_sats__: _number_ - - __paid_at_unix__: _number_ - - __service_fee_sats__: _number_ - - __service_url__: _string_ - - __swap_fee_sats__: _number_ - - __swap_operation_id__: _string_ - - __transaction_amount_sats__: _number_ - - __tx_id__: _string_ - -### InvoiceSwapQuoteList - - __quotes__: ARRAY of: _[InvoiceSwapQuote](#InvoiceSwapQuote)_ - -### InvoiceSwapRequest - - __amount_sats__: _number_ - -### InvoiceSwapsList - - __current_block_height__: _number_ - - __swaps__: ARRAY of: _[InvoiceSwapOperation](#InvoiceSwapOperation)_ - ### LatestBundleMetricReq - __limit__: _number_ *this field is optional @@ -1465,10 +1340,6 @@ The nostr server will send back a message response, and inside the body there wi ### LinkNPubThroughTokenRequest - __token__: _string_ -### LiquidityAssetProvider - - __pubkey__: _string_ - - __tracked__: _[TrackedLiquidityProvider](#TrackedLiquidityProvider)_ *this field is optional - ### LiveDebitRequest - __debit__: _[LiveDebitRequest_debit](#LiveDebitRequest_debit)_ - __npub__: _string_ @@ -1482,10 +1353,6 @@ The nostr server will send back a message response, and inside the body there wi - __latest_balance__: _number_ - __operation__: _[UserOperation](#UserOperation)_ -### LndAssetProvider - - __pubkey__: _string_ - - __tracked__: _[TrackedLndProvider](#TrackedLndProvider)_ *this field is optional - ### LndChannels - __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_ @@ -1667,11 +1534,6 @@ The nostr server will send back a message response, and inside the body there wi - __service_fee__: _number_ - __txId__: _string_ -### PayAdminInvoiceSwapRequest - - __no_claim__: _boolean_ *this field is optional - - __sat_per_v_byte__: _number_ - - __swap_operation_id__: _string_ - ### PayAdminTransactionSwapRequest - __address__: _string_ - __swap_operation_id__: _string_ @@ -1722,18 +1584,6 @@ The nostr server will send back a message response, and inside the body there wi ### ProvidersDisruption - __disruptions__: ARRAY of: _[ProviderDisruption](#ProviderDisruption)_ -### PushNotificationEnvelope - - __app_npub_hex__: _string_ - - __encrypted_payload__: _string_ - - __topic_id__: _string_ - -### PushNotificationPayload - - __data__: _[PushNotificationPayload_data](#PushNotificationPayload_data)_ - -### RefundAdminInvoiceSwapRequest - - __sat_per_v_byte__: _number_ - - __swap_operation_id__: _string_ - ### RelaysMigration - __relays__: ARRAY of: _string_ @@ -1790,31 +1640,19 @@ The nostr server will send back a message response, and inside the body there wi - __page__: _number_ - __request_id__: _number_ *this field is optional -### TrackedLiquidityProvider - - __balance__: _number_ - - __invoices__: ARRAY of: _[AssetOperation](#AssetOperation)_ - - __payments__: ARRAY of: _[AssetOperation](#AssetOperation)_ +### SwapOperation + - __address_paid__: _string_ + - __failure_reason__: _string_ *this field is optional + - __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional + - __swap_operation_id__: _string_ -### TrackedLndProvider - - __channels_balance__: _number_ - - __confirmed_balance__: _number_ - - __incoming_tx__: ARRAY of: _[AssetOperation](#AssetOperation)_ - - __invoices__: ARRAY of: _[AssetOperation](#AssetOperation)_ - - __outgoing_tx__: ARRAY of: _[AssetOperation](#AssetOperation)_ - - __payments__: ARRAY of: _[AssetOperation](#AssetOperation)_ - - __unconfirmed_balance__: _number_ - -### TrackedOperation - - __amount__: _number_ - - __ts__: _number_ - - __type__: _[TrackedOperationType](#TrackedOperationType)_ +### SwapsList + - __quotes__: ARRAY of: _[TransactionSwapQuote](#TransactionSwapQuote)_ + - __swaps__: ARRAY of: _[SwapOperation](#SwapOperation)_ ### TransactionSwapQuote - __chain_fee_sats__: _number_ - - __completed_at_unix__: _number_ - - __expires_at_block_height__: _number_ - __invoice_amount_sats__: _number_ - - __paid_at_unix__: _number_ - __service_fee_sats__: _number_ - __service_url__: _string_ - __swap_fee_sats__: _number_ @@ -1827,16 +1665,6 @@ The nostr server will send back a message response, and inside the body there wi ### TransactionSwapRequest - __transaction_amount_sats__: _number_ -### TxSwapOperation - - __address_paid__: _string_ *this field is optional - - __failure_reason__: _string_ *this field is optional - - __operation_payment__: _[UserOperation](#UserOperation)_ *this field is optional - - __quote__: _[TransactionSwapQuote](#TransactionSwapQuote)_ - - __tx_id__: _string_ *this field is optional - -### TxSwapsList - - __swaps__: ARRAY of: _[TxSwapOperation](#TxSwapOperation)_ - ### UpdateChannelPolicyRequest - __policy__: _[ChannelPolicy](#ChannelPolicy)_ - __update__: _[UpdateChannelPolicyRequest_update](#UpdateChannelPolicyRequest_update)_ @@ -1879,7 +1707,6 @@ The nostr server will send back a message response, and inside the body there wi - __nmanage__: _string_ - __noffer__: _string_ - __service_fee_bps__: _number_ - - __topic_id__: _string_ - __userId__: _string_ - __user_identifier__: _string_ @@ -1944,10 +1771,6 @@ The nostr server will send back a message response, and inside the body there wi - __BUNDLE_METRIC__ - __USAGE_METRIC__ -### TrackedOperationType - - __ROOT__ - - __USER__ - ### UserOperationType - __INCOMING_INVOICE__ - __INCOMING_TX__ diff --git a/proto/autogenerated/go/http_client.go b/proto/autogenerated/go/http_client.go index 43d60ce2..a2b0ecb0 100644 --- a/proto/autogenerated/go/http_client.go +++ b/proto/autogenerated/go/http_client.go @@ -66,7 +66,6 @@ type Client struct { BanDebit func(req DebitOperation) error BanUser func(req BanUserRequest) (*BanUserResponse, error) // batching method: BatchUser not implemented - BumpTx func(req BumpTx) error CloseChannel func(req CloseChannelRequest) (*CloseChannelResponse, error) CreateOneTimeInviteLink func(req CreateOneTimeInviteLinkRequest) (*CreateOneTimeInviteLinkResponse, error) DecodeInvoice func(req DecodeInvoiceRequest) (*DecodeInvoiceResponse, error) @@ -75,13 +74,11 @@ type Client struct { EncryptionExchange func(req EncryptionExchangeRequest) error EnrollAdminToken func(req EnrollAdminTokenRequest) error EnrollMessagingToken func(req MessagingToken) error - GetAdminInvoiceSwapQuotes func(req InvoiceSwapRequest) (*InvoiceSwapQuoteList, error) GetAdminTransactionSwapQuotes func(req TransactionSwapRequest) (*TransactionSwapQuoteList, error) GetApp func() (*Application, error) GetAppUser func(req GetAppUserRequest) (*AppUser, error) GetAppUserLNURLInfo func(req GetAppUserLNURLInfoRequest) (*LnurlPayInfoResponse, error) GetAppsMetrics func(req AppsMetricsRequest) (*AppsMetrics, error) - GetAssetsAndLiabilities func(req AssetsAndLiabilitiesReq) (*AssetsAndLiabilities, error) GetBundleMetrics func(req LatestBundleMetricReq) (*BundleMetrics, error) GetDebitAuthorizations func() (*DebitAuthorizations, error) GetErrorStats func() (*ErrorStats, error) @@ -117,22 +114,19 @@ type Client struct { HandleLnurlWithdraw func(query HandleLnurlWithdraw_Query) error Health func() error LinkNPubThroughToken func(req LinkNPubThroughTokenRequest) error - ListAdminInvoiceSwaps func() (*InvoiceSwapsList, error) - ListAdminTxSwaps func() (*TxSwapsList, error) + ListAdminSwaps func() (*SwapsList, error) ListChannels func() (*LndChannels, error) - ListTxSwaps func() (*TxSwapsList, error) + ListSwaps func() (*SwapsList, error) LndGetInfo func(req LndGetInfoRequest) (*LndGetInfoResponse, error) NewAddress func(req NewAddressRequest) (*NewAddressResponse, error) NewInvoice func(req NewInvoiceRequest) (*NewInvoiceResponse, error) NewProductInvoice func(query NewProductInvoice_Query) (*NewInvoiceResponse, error) OpenChannel func(req OpenChannelRequest) (*OpenChannelResponse, error) PayAddress func(req PayAddressRequest) (*PayAddressResponse, error) - PayAdminInvoiceSwap func(req PayAdminInvoiceSwapRequest) (*AdminInvoiceSwapResponse, error) - PayAdminTransactionSwap func(req PayAdminTransactionSwapRequest) (*AdminTxSwapResponse, error) + PayAdminTransactionSwap func(req PayAdminTransactionSwapRequest) (*AdminSwapResponse, error) PayAppUserInvoice func(req PayAppUserInvoiceRequest) (*PayInvoiceResponse, error) PayInvoice func(req PayInvoiceRequest) (*PayInvoiceResponse, error) PingSubProcesses func() error - RefundAdminInvoiceSwap func(req RefundAdminInvoiceSwapRequest) (*AdminInvoiceSwapResponse, error) RequestNPubLinkingToken func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) ResetDebit func(req DebitOperation) error ResetManage func(req ManageOperation) error @@ -466,30 +460,6 @@ func NewClient(params ClientParams) *Client { return &res, nil }, // batching method: BatchUser not implemented - BumpTx: func(req BumpTx) error { - auth, err := params.RetrieveAdminAuth() - if err != nil { - return err - } - finalRoute := "/api/admin/tx/bump" - body, err := json.Marshal(req) - if err != nil { - return err - } - resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) - if err != nil { - return err - } - result := ResultError{} - err = json.Unmarshal(resBody, &result) - if err != nil { - return err - } - if result.Status == "ERROR" { - return fmt.Errorf(result.Reason) - } - return nil - }, CloseChannel: func(req CloseChannelRequest) (*CloseChannelResponse, error) { auth, err := params.RetrieveAdminAuth() if err != nil { @@ -697,35 +667,6 @@ func NewClient(params ClientParams) *Client { } return nil }, - GetAdminInvoiceSwapQuotes: func(req InvoiceSwapRequest) (*InvoiceSwapQuoteList, error) { - auth, err := params.RetrieveAdminAuth() - if err != nil { - return nil, err - } - finalRoute := "/api/admin/swap/invoice/quote" - body, err := json.Marshal(req) - if err != nil { - return nil, err - } - resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) - if err != nil { - return nil, err - } - result := ResultError{} - err = json.Unmarshal(resBody, &result) - if err != nil { - return nil, err - } - if result.Status == "ERROR" { - return nil, fmt.Errorf(result.Reason) - } - res := InvoiceSwapQuoteList{} - err = json.Unmarshal(resBody, &res) - if err != nil { - return nil, err - } - return &res, nil - }, GetAdminTransactionSwapQuotes: func(req TransactionSwapRequest) (*TransactionSwapQuoteList, error) { auth, err := params.RetrieveAdminAuth() if err != nil { @@ -868,35 +809,6 @@ func NewClient(params ClientParams) *Client { } return &res, nil }, - GetAssetsAndLiabilities: func(req AssetsAndLiabilitiesReq) (*AssetsAndLiabilities, error) { - auth, err := params.RetrieveAdminAuth() - if err != nil { - return nil, err - } - finalRoute := "/api/admin/assets/liabilities" - body, err := json.Marshal(req) - if err != nil { - return nil, err - } - resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) - if err != nil { - return nil, err - } - result := ResultError{} - err = json.Unmarshal(resBody, &result) - if err != nil { - return nil, err - } - if result.Status == "ERROR" { - return nil, fmt.Errorf(result.Reason) - } - res := AssetsAndLiabilities{} - err = json.Unmarshal(resBody, &res) - if err != nil { - return nil, err - } - return &res, nil - }, GetBundleMetrics: func(req LatestBundleMetricReq) (*BundleMetrics, error) { auth, err := params.RetrieveMetricsAuth() if err != nil { @@ -1412,7 +1324,7 @@ func NewClient(params ClientParams) *Client { if err != nil { return nil, err } - finalRoute := "/api/user/swap/transaction/quote" + finalRoute := "/api/user/swap/quote" body, err := json.Marshal(req) if err != nil { return nil, err @@ -1731,12 +1643,12 @@ func NewClient(params ClientParams) *Client { } return nil }, - ListAdminInvoiceSwaps: func() (*InvoiceSwapsList, error) { + ListAdminSwaps: func() (*SwapsList, error) { auth, err := params.RetrieveAdminAuth() if err != nil { return nil, err } - finalRoute := "/api/admin/swap/invoice/list" + finalRoute := "/api/admin/swap/list" body := []byte{} resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) if err != nil { @@ -1750,33 +1662,7 @@ func NewClient(params ClientParams) *Client { if result.Status == "ERROR" { return nil, fmt.Errorf(result.Reason) } - res := InvoiceSwapsList{} - err = json.Unmarshal(resBody, &res) - if err != nil { - return nil, err - } - return &res, nil - }, - ListAdminTxSwaps: func() (*TxSwapsList, error) { - auth, err := params.RetrieveAdminAuth() - if err != nil { - return nil, err - } - finalRoute := "/api/admin/swap/transaction/list" - body := []byte{} - resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) - if err != nil { - return nil, err - } - result := ResultError{} - err = json.Unmarshal(resBody, &result) - if err != nil { - return nil, err - } - if result.Status == "ERROR" { - return nil, fmt.Errorf(result.Reason) - } - res := TxSwapsList{} + res := SwapsList{} err = json.Unmarshal(resBody, &res) if err != nil { return nil, err @@ -1805,12 +1691,12 @@ func NewClient(params ClientParams) *Client { } return &res, nil }, - ListTxSwaps: func() (*TxSwapsList, error) { + ListSwaps: func() (*SwapsList, error) { auth, err := params.RetrieveUserAuth() if err != nil { return nil, err } - finalRoute := "/api/user/swap/transaction/list" + finalRoute := "/api/user/swap/list" body := []byte{} resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) if err != nil { @@ -1824,7 +1710,7 @@ func NewClient(params ClientParams) *Client { if result.Status == "ERROR" { return nil, fmt.Errorf(result.Reason) } - res := TxSwapsList{} + res := SwapsList{} err = json.Unmarshal(resBody, &res) if err != nil { return nil, err @@ -2006,36 +1892,7 @@ func NewClient(params ClientParams) *Client { } return &res, nil }, - PayAdminInvoiceSwap: func(req PayAdminInvoiceSwapRequest) (*AdminInvoiceSwapResponse, error) { - auth, err := params.RetrieveAdminAuth() - if err != nil { - return nil, err - } - finalRoute := "/api/admin/swap/invoice/pay" - body, err := json.Marshal(req) - if err != nil { - return nil, err - } - resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) - if err != nil { - return nil, err - } - result := ResultError{} - err = json.Unmarshal(resBody, &result) - if err != nil { - return nil, err - } - if result.Status == "ERROR" { - return nil, fmt.Errorf(result.Reason) - } - res := AdminInvoiceSwapResponse{} - err = json.Unmarshal(resBody, &res) - if err != nil { - return nil, err - } - return &res, nil - }, - PayAdminTransactionSwap: func(req PayAdminTransactionSwapRequest) (*AdminTxSwapResponse, error) { + PayAdminTransactionSwap: func(req PayAdminTransactionSwapRequest) (*AdminSwapResponse, error) { auth, err := params.RetrieveAdminAuth() if err != nil { return nil, err @@ -2057,7 +1914,7 @@ func NewClient(params ClientParams) *Client { if result.Status == "ERROR" { return nil, fmt.Errorf(result.Reason) } - res := AdminTxSwapResponse{} + res := AdminSwapResponse{} err = json.Unmarshal(resBody, &res) if err != nil { return nil, err @@ -2143,35 +2000,6 @@ func NewClient(params ClientParams) *Client { } return nil }, - RefundAdminInvoiceSwap: func(req RefundAdminInvoiceSwapRequest) (*AdminInvoiceSwapResponse, error) { - auth, err := params.RetrieveAdminAuth() - if err != nil { - return nil, err - } - finalRoute := "/api/admin/swap/invoice/refund" - body, err := json.Marshal(req) - if err != nil { - return nil, err - } - resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) - if err != nil { - return nil, err - } - result := ResultError{} - err = json.Unmarshal(resBody, &result) - if err != nil { - return nil, err - } - if result.Status == "ERROR" { - return nil, fmt.Errorf(result.Reason) - } - res := AdminInvoiceSwapResponse{} - err = json.Unmarshal(resBody, &res) - if err != nil { - return nil, err - } - return &res, nil - }, RequestNPubLinkingToken: func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) { auth, err := params.RetrieveAppAuth() if err != nil { diff --git a/proto/autogenerated/go/types.go b/proto/autogenerated/go/types.go index cff46783..841ced1d 100644 --- a/proto/autogenerated/go/types.go +++ b/proto/autogenerated/go/types.go @@ -79,13 +79,6 @@ const ( USAGE_METRIC SingleMetricType = "USAGE_METRIC" ) -type TrackedOperationType string - -const ( - ROOT TrackedOperationType = "ROOT" - USER TrackedOperationType = "USER" -) - type UserOperationType string const ( @@ -130,10 +123,7 @@ type AddProductRequest struct { Name string `json:"name"` Price_sats int64 `json:"price_sats"` } -type AdminInvoiceSwapResponse struct { - Tx_id string `json:"tx_id"` -} -type AdminTxSwapResponse struct { +type AdminSwapResponse struct { Network_fee int64 `json:"network_fee"` Tx_id string `json:"tx_id"` } @@ -170,21 +160,6 @@ type AppsMetricsRequest struct { Include_operations bool `json:"include_operations"` To_unix int64 `json:"to_unix"` } -type AssetOperation struct { - Amount int64 `json:"amount"` - Tracked *TrackedOperation `json:"tracked"` - Ts int64 `json:"ts"` -} -type AssetsAndLiabilities struct { - Liquidity_providers []LiquidityAssetProvider `json:"liquidity_providers"` - Lnds []LndAssetProvider `json:"lnds"` - Users_balance int64 `json:"users_balance"` -} -type AssetsAndLiabilitiesReq struct { - Limit_invoices int64 `json:"limit_invoices"` - Limit_payments int64 `json:"limit_payments"` - Limit_providers int64 `json:"limit_providers"` -} type AuthApp struct { App *Application `json:"app"` Auth_token string `json:"auth_token"` @@ -213,11 +188,6 @@ type BeaconData struct { Nextrelay string `json:"nextRelay"` Type string `json:"type"` } -type BumpTx struct { - Output_index int64 `json:"output_index"` - Sat_per_vbyte int64 `json:"sat_per_vbyte"` - Txid string `json:"txid"` -} type BundleData struct { Available_chunks []int64 `json:"available_chunks"` Base_64_data []string `json:"base_64_data"` @@ -386,36 +356,6 @@ type HttpCreds struct { Token string `json:"token"` Url string `json:"url"` } -type InvoiceSwapOperation struct { - Completed_at_unix int64 `json:"completed_at_unix"` - Failure_reason string `json:"failure_reason"` - Operation_payment *UserOperation `json:"operation_payment"` - Quote *InvoiceSwapQuote `json:"quote"` -} -type InvoiceSwapQuote struct { - Address string `json:"address"` - Chain_fee_sats int64 `json:"chain_fee_sats"` - Expires_at_block_height int64 `json:"expires_at_block_height"` - Invoice string `json:"invoice"` - 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_url string `json:"service_url"` - Swap_fee_sats int64 `json:"swap_fee_sats"` - Swap_operation_id string `json:"swap_operation_id"` - Transaction_amount_sats int64 `json:"transaction_amount_sats"` - Tx_id string `json:"tx_id"` -} -type InvoiceSwapQuoteList struct { - Quotes []InvoiceSwapQuote `json:"quotes"` -} -type InvoiceSwapRequest struct { - Amount_sats int64 `json:"amount_sats"` -} -type InvoiceSwapsList struct { - Current_block_height int64 `json:"current_block_height"` - Swaps []InvoiceSwapOperation `json:"swaps"` -} type LatestBundleMetricReq struct { Limit int64 `json:"limit"` } @@ -425,10 +365,6 @@ type LatestUsageMetricReq struct { type LinkNPubThroughTokenRequest struct { Token string `json:"token"` } -type LiquidityAssetProvider struct { - Pubkey string `json:"pubkey"` - Tracked *TrackedLiquidityProvider `json:"tracked"` -} type LiveDebitRequest struct { Debit *LiveDebitRequest_debit `json:"debit"` Npub string `json:"npub"` @@ -442,10 +378,6 @@ type LiveUserOperation struct { Latest_balance int64 `json:"latest_balance"` Operation *UserOperation `json:"operation"` } -type LndAssetProvider struct { - Pubkey string `json:"pubkey"` - Tracked *TrackedLndProvider `json:"tracked"` -} type LndChannels struct { Open_channels []OpenChannel `json:"open_channels"` } @@ -627,11 +559,6 @@ type PayAddressResponse struct { Service_fee int64 `json:"service_fee"` Txid string `json:"txId"` } -type PayAdminInvoiceSwapRequest struct { - No_claim bool `json:"no_claim"` - Sat_per_v_byte int64 `json:"sat_per_v_byte"` - Swap_operation_id string `json:"swap_operation_id"` -} type PayAdminTransactionSwapRequest struct { Address string `json:"address"` Swap_operation_id string `json:"swap_operation_id"` @@ -682,18 +609,6 @@ type ProviderDisruption struct { type ProvidersDisruption struct { Disruptions []ProviderDisruption `json:"disruptions"` } -type PushNotificationEnvelope struct { - App_npub_hex string `json:"app_npub_hex"` - Encrypted_payload string `json:"encrypted_payload"` - Topic_id string `json:"topic_id"` -} -type PushNotificationPayload struct { - Data *PushNotificationPayload_data `json:"data"` -} -type RefundAdminInvoiceSwapRequest struct { - Sat_per_v_byte int64 `json:"sat_per_v_byte"` - Swap_operation_id string `json:"swap_operation_id"` -} type RelaysMigration struct { Relays []string `json:"relays"` } @@ -750,31 +665,19 @@ type SingleMetricReq struct { Page int64 `json:"page"` Request_id int64 `json:"request_id"` } -type TrackedLiquidityProvider struct { - Balance int64 `json:"balance"` - Invoices []AssetOperation `json:"invoices"` - Payments []AssetOperation `json:"payments"` +type SwapOperation struct { + Address_paid string `json:"address_paid"` + Failure_reason string `json:"failure_reason"` + Operation_payment *UserOperation `json:"operation_payment"` + Swap_operation_id string `json:"swap_operation_id"` } -type TrackedLndProvider struct { - Channels_balance int64 `json:"channels_balance"` - Confirmed_balance int64 `json:"confirmed_balance"` - Incoming_tx []AssetOperation `json:"incoming_tx"` - Invoices []AssetOperation `json:"invoices"` - Outgoing_tx []AssetOperation `json:"outgoing_tx"` - Payments []AssetOperation `json:"payments"` - Unconfirmed_balance int64 `json:"unconfirmed_balance"` -} -type TrackedOperation struct { - Amount int64 `json:"amount"` - Ts int64 `json:"ts"` - Type TrackedOperationType `json:"type"` +type SwapsList struct { + Quotes []TransactionSwapQuote `json:"quotes"` + Swaps []SwapOperation `json:"swaps"` } type TransactionSwapQuote struct { Chain_fee_sats int64 `json:"chain_fee_sats"` - Completed_at_unix int64 `json:"completed_at_unix"` - Expires_at_block_height int64 `json:"expires_at_block_height"` 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_url string `json:"service_url"` Swap_fee_sats int64 `json:"swap_fee_sats"` @@ -787,16 +690,6 @@ type TransactionSwapQuoteList struct { type TransactionSwapRequest struct { Transaction_amount_sats int64 `json:"transaction_amount_sats"` } -type TxSwapOperation struct { - Address_paid string `json:"address_paid"` - Failure_reason string `json:"failure_reason"` - Operation_payment *UserOperation `json:"operation_payment"` - Quote *TransactionSwapQuote `json:"quote"` - Tx_id string `json:"tx_id"` -} -type TxSwapsList struct { - Swaps []TxSwapOperation `json:"swaps"` -} type UpdateChannelPolicyRequest struct { Policy *ChannelPolicy `json:"policy"` Update *UpdateChannelPolicyRequest_update `json:"update"` @@ -839,7 +732,6 @@ type UserInfo struct { Nmanage string `json:"nmanage"` Noffer string `json:"noffer"` Service_fee_bps int64 `json:"service_fee_bps"` - Topic_id string `json:"topic_id"` Userid string `json:"userId"` User_identifier string `json:"user_identifier"` } @@ -938,18 +830,6 @@ type NPubLinking_state struct { Linking_token *string `json:"linking_token"` Unlinked *Empty `json:"unlinked"` } -type PushNotificationPayload_data_type string - -const ( - RECEIVED_OPERATION PushNotificationPayload_data_type = "received_operation" - SENT_OPERATION PushNotificationPayload_data_type = "sent_operation" -) - -type PushNotificationPayload_data struct { - Type PushNotificationPayload_data_type `json:"type"` - Received_operation *UserOperation `json:"received_operation"` - Sent_operation *UserOperation `json:"sent_operation"` -} type UpdateChannelPolicyRequest_update_type string const ( diff --git a/proto/autogenerated/ts/express_server.ts b/proto/autogenerated/ts/express_server.ts index aa809166..c1740acd 100644 --- a/proto/autogenerated/ts/express_server.ts +++ b/proto/autogenerated/ts/express_server.ts @@ -545,12 +545,12 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } break - case 'ListTxSwaps': - if (!methods.ListTxSwaps) { - throw new Error('method ListTxSwaps not found' ) + case 'ListSwaps': + if (!methods.ListSwaps) { + throw new Error('method ListSwaps not found' ) } else { opStats.validate = opStats.guard - const res = await methods.ListTxSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res }) + const res = await methods.ListSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res }) opStats.handle = process.hrtime.bigint() callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } @@ -693,28 +693,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.BumpTx) throw new Error('method: BumpTx is not implemented') - app.post('/api/admin/tx/bump', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'BumpTx', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.BumpTx) throw new Error('method: BumpTx is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.BumpTxValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.BumpTx({rpcName:'BumpTx', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) if (!opts.allowNotImplementedMethods && !methods.CloseChannel) throw new Error('method: CloseChannel is not implemented') app.post('/api/admin/channel/close', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'CloseChannel', batch: false, nostr: false, batchSize: 0} @@ -891,28 +869,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.GetAdminInvoiceSwapQuotes) throw new Error('method: GetAdminInvoiceSwapQuotes is not implemented') - app.post('/api/admin/swap/invoice/quote', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetAdminInvoiceSwapQuotes', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetAdminInvoiceSwapQuotes) throw new Error('method: GetAdminInvoiceSwapQuotes is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.InvoiceSwapRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetAdminInvoiceSwapQuotes({rpcName:'GetAdminInvoiceSwapQuotes', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) if (!opts.allowNotImplementedMethods && !methods.GetAdminTransactionSwapQuotes) throw new Error('method: GetAdminTransactionSwapQuotes is not implemented') app.post('/api/admin/swap/transaction/quote', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'GetAdminTransactionSwapQuotes', batch: false, nostr: false, batchSize: 0} @@ -1020,28 +976,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.GetAssetsAndLiabilities) throw new Error('method: GetAssetsAndLiabilities is not implemented') - app.post('/api/admin/assets/liabilities', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetAssetsAndLiabilities', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetAssetsAndLiabilities) throw new Error('method: GetAssetsAndLiabilities is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AssetsAndLiabilitiesReqValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetAssetsAndLiabilities({rpcName:'GetAssetsAndLiabilities', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) if (!opts.allowNotImplementedMethods && !methods.GetBundleMetrics) throw new Error('method: GetBundleMetrics is not implemented') app.post('/api/reports/bundle', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'GetBundleMetrics', batch: false, nostr: false, batchSize: 0} @@ -1428,7 +1362,7 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) if (!opts.allowNotImplementedMethods && !methods.GetTransactionSwapQuotes) throw new Error('method: GetTransactionSwapQuotes is not implemented') - app.post('/api/user/swap/transaction/quote', async (req, res) => { + app.post('/api/user/swap/quote', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'GetTransactionSwapQuotes', batch: false, nostr: false, batchSize: 0} const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } let authCtx: Types.AuthContext = {} @@ -1673,39 +1607,20 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.ListAdminInvoiceSwaps) throw new Error('method: ListAdminInvoiceSwaps is not implemented') - app.post('/api/admin/swap/invoice/list', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'ListAdminInvoiceSwaps', batch: false, nostr: false, batchSize: 0} + if (!opts.allowNotImplementedMethods && !methods.ListAdminSwaps) throw new Error('method: ListAdminSwaps is not implemented') + app.post('/api/admin/swap/list', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'ListAdminSwaps', batch: false, nostr: false, batchSize: 0} const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } let authCtx: Types.AuthContext = {} try { - if (!methods.ListAdminInvoiceSwaps) throw new Error('method: ListAdminInvoiceSwaps is not implemented') + if (!methods.ListAdminSwaps) throw new Error('method: ListAdminSwaps is not implemented') const authContext = await opts.AdminAuthGuard(req.headers['authorization']) authCtx = authContext stats.guard = process.hrtime.bigint() stats.validate = stats.guard const query = req.query const params = req.params - const response = await methods.ListAdminInvoiceSwaps({rpcName:'ListAdminInvoiceSwaps', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.ListAdminTxSwaps) throw new Error('method: ListAdminTxSwaps is not implemented') - app.post('/api/admin/swap/transaction/list', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'ListAdminTxSwaps', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.ListAdminTxSwaps) throw new Error('method: ListAdminTxSwaps is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.ListAdminTxSwaps({rpcName:'ListAdminTxSwaps', ctx:authContext }) + const response = await methods.ListAdminSwaps({rpcName:'ListAdminSwaps', ctx:authContext }) stats.handle = process.hrtime.bigint() res.json({status: 'OK', ...response}) opts.metricsCallback([{ ...info, ...stats, ...authContext }]) @@ -1730,20 +1645,20 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.ListTxSwaps) throw new Error('method: ListTxSwaps is not implemented') - app.post('/api/user/swap/transaction/list', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'ListTxSwaps', batch: false, nostr: false, batchSize: 0} + if (!opts.allowNotImplementedMethods && !methods.ListSwaps) throw new Error('method: ListSwaps is not implemented') + app.post('/api/user/swap/list', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'ListSwaps', batch: false, nostr: false, batchSize: 0} const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } let authCtx: Types.AuthContext = {} try { - if (!methods.ListTxSwaps) throw new Error('method: ListTxSwaps is not implemented') + if (!methods.ListSwaps) throw new Error('method: ListSwaps is not implemented') const authContext = await opts.UserAuthGuard(req.headers['authorization']) authCtx = authContext stats.guard = process.hrtime.bigint() stats.validate = stats.guard const query = req.query const params = req.params - const response = await methods.ListTxSwaps({rpcName:'ListTxSwaps', ctx:authContext }) + const response = await methods.ListSwaps({rpcName:'ListSwaps', ctx:authContext }) stats.handle = process.hrtime.bigint() res.json({status: 'OK', ...response}) opts.metricsCallback([{ ...info, ...stats, ...authContext }]) @@ -1878,28 +1793,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.PayAdminInvoiceSwap) throw new Error('method: PayAdminInvoiceSwap is not implemented') - app.post('/api/admin/swap/invoice/pay', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'PayAdminInvoiceSwap', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.PayAdminInvoiceSwap) throw new Error('method: PayAdminInvoiceSwap is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.PayAdminInvoiceSwapRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.PayAdminInvoiceSwap({rpcName:'PayAdminInvoiceSwap', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) if (!opts.allowNotImplementedMethods && !methods.PayAdminTransactionSwap) throw new Error('method: PayAdminTransactionSwap is not implemented') app.post('/api/admin/swap/transaction/pay', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'PayAdminTransactionSwap', batch: false, nostr: false, batchSize: 0} @@ -1985,28 +1878,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.RefundAdminInvoiceSwap) throw new Error('method: RefundAdminInvoiceSwap is not implemented') - app.post('/api/admin/swap/invoice/refund', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'RefundAdminInvoiceSwap', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.RefundAdminInvoiceSwap) throw new Error('method: RefundAdminInvoiceSwap is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.RefundAdminInvoiceSwapRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.RefundAdminInvoiceSwap({rpcName:'RefundAdminInvoiceSwap', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) if (!opts.allowNotImplementedMethods && !methods.RequestNPubLinkingToken) throw new Error('method: RequestNPubLinkingToken is not implemented') app.post('/api/app/user/npub/token', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'RequestNPubLinkingToken', batch: false, nostr: false, batchSize: 0} diff --git a/proto/autogenerated/ts/http_client.ts b/proto/autogenerated/ts/http_client.ts index 21597e2c..a24ff3e6 100644 --- a/proto/autogenerated/ts/http_client.ts +++ b/proto/autogenerated/ts/http_client.ts @@ -176,17 +176,6 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - BumpTx: async (request: Types.BumpTx): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/tx/bump' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, CloseChannel: async (request: Types.CloseChannelRequest): Promise => { const auth = await params.retrieveAdminAuth() if (auth === null) throw new Error('retrieveAdminAuth() returned null') @@ -284,20 +273,6 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - GetAdminInvoiceSwapQuotes: async (request: Types.InvoiceSwapRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/swap/invoice/quote' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.InvoiceSwapQuoteListValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, GetAdminTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise => { const auth = await params.retrieveAdminAuth() if (auth === null) throw new Error('retrieveAdminAuth() returned null') @@ -368,20 +343,6 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - GetAssetsAndLiabilities: async (request: Types.AssetsAndLiabilitiesReq): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/assets/liabilities' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AssetsAndLiabilitiesValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, GetBundleMetrics: async (request: Types.LatestBundleMetricReq): Promise => { const auth = await params.retrieveMetricsAuth() if (auth === null) throw new Error('retrieveMetricsAuth() returned null') @@ -659,7 +620,7 @@ export default (params: ClientParams) => ({ GetTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise => { const auth = await params.retrieveUserAuth() if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/swap/transaction/quote' + let finalRoute = '/api/user/swap/quote' const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { @@ -820,30 +781,16 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - ListAdminInvoiceSwaps: async (): Promise => { + ListAdminSwaps: async (): Promise => { const auth = await params.retrieveAdminAuth() if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/swap/invoice/list' + let finalRoute = '/api/admin/swap/list' const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.InvoiceSwapsListValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - ListAdminTxSwaps: async (): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/swap/transaction/list' - const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.TxSwapsListValidate(result) + const error = Types.SwapsListValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -862,16 +809,16 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - ListTxSwaps: async (): Promise => { + ListSwaps: async (): Promise => { const auth = await params.retrieveUserAuth() if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/swap/transaction/list' + let finalRoute = '/api/user/swap/list' const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.TxSwapsListValidate(result) + const error = Types.SwapsListValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -962,21 +909,7 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - PayAdminInvoiceSwap: async (request: Types.PayAdminInvoiceSwapRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/swap/invoice/pay' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AdminInvoiceSwapResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise => { + PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise => { const auth = await params.retrieveAdminAuth() if (auth === null) throw new Error('retrieveAdminAuth() returned null') let finalRoute = '/api/admin/swap/transaction/pay' @@ -985,7 +918,7 @@ export default (params: ClientParams) => ({ if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AdminTxSwapResponseValidate(result) + const error = Types.AdminSwapResponseValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -1029,20 +962,6 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - RefundAdminInvoiceSwap: async (request: Types.RefundAdminInvoiceSwapRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/swap/invoice/refund' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AdminInvoiceSwapResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, RequestNPubLinkingToken: async (request: Types.RequestNPubLinkingTokenRequest): Promise => { const auth = await params.retrieveAppAuth() if (auth === null) throw new Error('retrieveAppAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_client.ts b/proto/autogenerated/ts/nostr_client.ts index 64e517e6..df969c7b 100644 --- a/proto/autogenerated/ts/nostr_client.ts +++ b/proto/autogenerated/ts/nostr_client.ts @@ -137,18 +137,6 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - BumpTx: async (request: Types.BumpTx): Promise => { - const auth = await params.retrieveNostrAdminAuth() - if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'BumpTx',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, CloseChannel: async (request: Types.CloseChannelRequest): Promise => { const auth = await params.retrieveNostrAdminAuth() if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') @@ -242,21 +230,6 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - GetAdminInvoiceSwapQuotes: async (request: Types.InvoiceSwapRequest): Promise => { - const auth = await params.retrieveNostrAdminAuth() - if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'GetAdminInvoiceSwapQuotes',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.InvoiceSwapQuoteListValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, GetAdminTransactionSwapQuotes: async (request: Types.TransactionSwapRequest): Promise => { const auth = await params.retrieveNostrAdminAuth() if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') @@ -287,21 +260,6 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - GetAssetsAndLiabilities: async (request: Types.AssetsAndLiabilitiesReq): Promise => { - const auth = await params.retrieveNostrAdminAuth() - if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'GetAssetsAndLiabilities',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AssetsAndLiabilitiesValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, GetBundleMetrics: async (request: Types.LatestBundleMetricReq): Promise => { const auth = await params.retrieveNostrMetricsAuth() if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') @@ -708,30 +666,16 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - ListAdminInvoiceSwaps: async (): Promise => { + ListAdminSwaps: async (): Promise => { const auth = await params.retrieveNostrAdminAuth() if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'ListAdminInvoiceSwaps',authIdentifier:auth, ...nostrRequest }) + const data = await send(params.pubDestination, {rpcName:'ListAdminSwaps',authIdentifier:auth, ...nostrRequest }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.InvoiceSwapsListValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - ListAdminTxSwaps: async (): Promise => { - const auth = await params.retrieveNostrAdminAuth() - if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') - const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'ListAdminTxSwaps',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.TxSwapsListValidate(result) + const error = Types.SwapsListValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -750,16 +694,16 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - ListTxSwaps: async (): Promise => { + ListSwaps: async (): Promise => { const auth = await params.retrieveNostrUserAuth() if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'ListTxSwaps',authIdentifier:auth, ...nostrRequest }) + const data = await send(params.pubDestination, {rpcName:'ListSwaps',authIdentifier:auth, ...nostrRequest }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.TxSwapsListValidate(result) + const error = Types.SwapsListValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -854,22 +798,7 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - PayAdminInvoiceSwap: async (request: Types.PayAdminInvoiceSwapRequest): Promise => { - const auth = await params.retrieveNostrAdminAuth() - if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'PayAdminInvoiceSwap',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AdminInvoiceSwapResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise => { + PayAdminTransactionSwap: async (request: Types.PayAdminTransactionSwapRequest): Promise => { const auth = await params.retrieveNostrAdminAuth() if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') const nostrRequest: NostrRequest = {} @@ -879,7 +808,7 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AdminTxSwapResponseValidate(result) + const error = Types.AdminSwapResponseValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -910,21 +839,6 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - RefundAdminInvoiceSwap: async (request: Types.RefundAdminInvoiceSwapRequest): Promise => { - const auth = await params.retrieveNostrAdminAuth() - if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'RefundAdminInvoiceSwap',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AdminInvoiceSwapResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, ResetDebit: async (request: Types.DebitOperation): Promise => { const auth = await params.retrieveNostrUserAuth() if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_transport.ts b/proto/autogenerated/ts/nostr_transport.ts index 80284e10..24a96cd6 100644 --- a/proto/autogenerated/ts/nostr_transport.ts +++ b/proto/autogenerated/ts/nostr_transport.ts @@ -427,12 +427,12 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } break - case 'ListTxSwaps': - if (!methods.ListTxSwaps) { - throw new Error('method not defined: ListTxSwaps') + case 'ListSwaps': + if (!methods.ListSwaps) { + throw new Error('method not defined: ListSwaps') } else { opStats.validate = opStats.guard - const res = await methods.ListTxSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res }) + const res = await methods.ListSwaps({...operation, ctx}); responses.push({ status: 'OK', ...res }) opStats.handle = process.hrtime.bigint() callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } @@ -575,22 +575,6 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'BumpTx': - try { - if (!methods.BumpTx) throw new Error('method: BumpTx is not implemented') - const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.BumpTxValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - await methods.BumpTx({rpcName:'BumpTx', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break case 'CloseChannel': try { if (!methods.CloseChannel) throw new Error('method: CloseChannel is not implemented') @@ -703,22 +687,6 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'GetAdminInvoiceSwapQuotes': - try { - if (!methods.GetAdminInvoiceSwapQuotes) throw new Error('method: GetAdminInvoiceSwapQuotes is not implemented') - const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.InvoiceSwapRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.GetAdminInvoiceSwapQuotes({rpcName:'GetAdminInvoiceSwapQuotes', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break case 'GetAdminTransactionSwapQuotes': try { if (!methods.GetAdminTransactionSwapQuotes) throw new Error('method: GetAdminTransactionSwapQuotes is not implemented') @@ -751,22 +719,6 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'GetAssetsAndLiabilities': - try { - if (!methods.GetAssetsAndLiabilities) throw new Error('method: GetAssetsAndLiabilities is not implemented') - const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.AssetsAndLiabilitiesReqValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.GetAssetsAndLiabilities({rpcName:'GetAssetsAndLiabilities', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break case 'GetBundleMetrics': try { if (!methods.GetBundleMetrics) throw new Error('method: GetBundleMetrics is not implemented') @@ -1170,27 +1122,14 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'ListAdminInvoiceSwaps': + case 'ListAdminSwaps': try { - if (!methods.ListAdminInvoiceSwaps) throw new Error('method: ListAdminInvoiceSwaps is not implemented') + if (!methods.ListAdminSwaps) throw new Error('method: ListAdminSwaps is not implemented') const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) stats.guard = process.hrtime.bigint() authCtx = authContext stats.validate = stats.guard - const response = await methods.ListAdminInvoiceSwaps({rpcName:'ListAdminInvoiceSwaps', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'ListAdminTxSwaps': - try { - if (!methods.ListAdminTxSwaps) throw new Error('method: ListAdminTxSwaps is not implemented') - const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - const response = await methods.ListAdminTxSwaps({rpcName:'ListAdminTxSwaps', ctx:authContext }) + const response = await methods.ListAdminSwaps({rpcName:'ListAdminSwaps', ctx:authContext }) stats.handle = process.hrtime.bigint() res({status: 'OK', ...response}) opts.metricsCallback([{ ...info, ...stats, ...authContext }]) @@ -1209,14 +1148,14 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'ListTxSwaps': + case 'ListSwaps': try { - if (!methods.ListTxSwaps) throw new Error('method: ListTxSwaps is not implemented') + if (!methods.ListSwaps) throw new Error('method: ListSwaps is not implemented') const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) stats.guard = process.hrtime.bigint() authCtx = authContext stats.validate = stats.guard - const response = await methods.ListTxSwaps({rpcName:'ListTxSwaps', ctx:authContext }) + const response = await methods.ListSwaps({rpcName:'ListSwaps', ctx:authContext }) stats.handle = process.hrtime.bigint() res({status: 'OK', ...response}) opts.metricsCallback([{ ...info, ...stats, ...authContext }]) @@ -1315,22 +1254,6 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'PayAdminInvoiceSwap': - try { - if (!methods.PayAdminInvoiceSwap) throw new Error('method: PayAdminInvoiceSwap is not implemented') - const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.PayAdminInvoiceSwapRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.PayAdminInvoiceSwap({rpcName:'PayAdminInvoiceSwap', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break case 'PayAdminTransactionSwap': try { if (!methods.PayAdminTransactionSwap) throw new Error('method: PayAdminTransactionSwap is not implemented') @@ -1376,22 +1299,6 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'RefundAdminInvoiceSwap': - try { - if (!methods.RefundAdminInvoiceSwap) throw new Error('method: RefundAdminInvoiceSwap is not implemented') - const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.RefundAdminInvoiceSwapRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.RefundAdminInvoiceSwap({rpcName:'RefundAdminInvoiceSwap', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break case 'ResetDebit': try { if (!methods.ResetDebit) throw new Error('method: ResetDebit is not implemented') diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index 90cd1724..e397cd94 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -7,8 +7,8 @@ export type RequestMetric = AuthContext & RequestInfo & RequestStats & { error?: export type AdminContext = { admin_id: string } -export type AdminMethodInputs = AddApp_Input | AddPeer_Input | AuthApp_Input | BanUser_Input | BumpTx_Input | CloseChannel_Input | CreateOneTimeInviteLink_Input | GetAdminInvoiceSwapQuotes_Input | GetAdminTransactionSwapQuotes_Input | GetAssetsAndLiabilities_Input | GetInviteLinkState_Input | GetSeed_Input | ListAdminInvoiceSwaps_Input | ListAdminTxSwaps_Input | ListChannels_Input | LndGetInfo_Input | OpenChannel_Input | PayAdminInvoiceSwap_Input | PayAdminTransactionSwap_Input | RefundAdminInvoiceSwap_Input | UpdateChannelPolicy_Input -export type AdminMethodOutputs = AddApp_Output | AddPeer_Output | AuthApp_Output | BanUser_Output | BumpTx_Output | CloseChannel_Output | CreateOneTimeInviteLink_Output | GetAdminInvoiceSwapQuotes_Output | GetAdminTransactionSwapQuotes_Output | GetAssetsAndLiabilities_Output | GetInviteLinkState_Output | GetSeed_Output | ListAdminInvoiceSwaps_Output | ListAdminTxSwaps_Output | ListChannels_Output | LndGetInfo_Output | OpenChannel_Output | PayAdminInvoiceSwap_Output | PayAdminTransactionSwap_Output | RefundAdminInvoiceSwap_Output | UpdateChannelPolicy_Output +export type AdminMethodInputs = AddApp_Input | AddPeer_Input | AuthApp_Input | BanUser_Input | CloseChannel_Input | CreateOneTimeInviteLink_Input | GetAdminTransactionSwapQuotes_Input | GetInviteLinkState_Input | GetSeed_Input | ListAdminSwaps_Input | ListChannels_Input | LndGetInfo_Input | OpenChannel_Input | PayAdminTransactionSwap_Input | UpdateChannelPolicy_Input +export type AdminMethodOutputs = AddApp_Output | AddPeer_Output | AuthApp_Output | BanUser_Output | CloseChannel_Output | CreateOneTimeInviteLink_Output | GetAdminTransactionSwapQuotes_Output | GetInviteLinkState_Output | GetSeed_Output | ListAdminSwaps_Output | ListChannels_Output | LndGetInfo_Output | OpenChannel_Output | PayAdminTransactionSwap_Output | UpdateChannelPolicy_Output export type AppContext = { app_id: string } @@ -35,8 +35,8 @@ export type UserContext = { app_user_id: string user_id: string } -export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeManage_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | EnrollMessagingToken_Input | GetDebitAuthorizations_Input | GetHttpCreds_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetManageAuthorizations_Input | GetPaymentState_Input | GetTransactionSwapQuotes_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | ListTxSwaps_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | ResetManage_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input -export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeManage_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | EnrollMessagingToken_Output | GetDebitAuthorizations_Output | GetHttpCreds_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetManageAuthorizations_Output | GetPaymentState_Output | GetTransactionSwapQuotes_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | ListTxSwaps_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | ResetManage_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output +export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeManage_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | EnrollMessagingToken_Input | GetDebitAuthorizations_Input | GetHttpCreds_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetManageAuthorizations_Input | GetPaymentState_Input | GetTransactionSwapQuotes_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | ListSwaps_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | ResetManage_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input +export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeManage_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | EnrollMessagingToken_Output | GetDebitAuthorizations_Output | GetHttpCreds_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetManageAuthorizations_Output | GetPaymentState_Output | GetTransactionSwapQuotes_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | ListSwaps_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | ResetManage_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest} @@ -75,9 +75,6 @@ export type BanUser_Output = ResultError | ({ status: 'OK' } & BanUserResponse) export type BatchUser_Input = UserMethodInputs export type BatchUser_Output = UserMethodOutputs -export type BumpTx_Input = {rpcName:'BumpTx', req: BumpTx} -export type BumpTx_Output = ResultError | { status: 'OK' } - export type CloseChannel_Input = {rpcName:'CloseChannel', req: CloseChannelRequest} export type CloseChannel_Output = ResultError | ({ status: 'OK' } & CloseChannelResponse) @@ -102,9 +99,6 @@ export type EnrollAdminToken_Output = ResultError | { status: 'OK' } export type EnrollMessagingToken_Input = {rpcName:'EnrollMessagingToken', req: MessagingToken} export type EnrollMessagingToken_Output = ResultError | { status: 'OK' } -export type GetAdminInvoiceSwapQuotes_Input = {rpcName:'GetAdminInvoiceSwapQuotes', req: InvoiceSwapRequest} -export type GetAdminInvoiceSwapQuotes_Output = ResultError | ({ status: 'OK' } & InvoiceSwapQuoteList) - export type GetAdminTransactionSwapQuotes_Input = {rpcName:'GetAdminTransactionSwapQuotes', req: TransactionSwapRequest} export type GetAdminTransactionSwapQuotes_Output = ResultError | ({ status: 'OK' } & TransactionSwapQuoteList) @@ -120,9 +114,6 @@ export type GetAppUserLNURLInfo_Output = ResultError | ({ status: 'OK' } & Lnurl export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest} export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics) -export type GetAssetsAndLiabilities_Input = {rpcName:'GetAssetsAndLiabilities', req: AssetsAndLiabilitiesReq} -export type GetAssetsAndLiabilities_Output = ResultError | ({ status: 'OK' } & AssetsAndLiabilities) - export type GetBundleMetrics_Input = {rpcName:'GetBundleMetrics', req: LatestBundleMetricReq} export type GetBundleMetrics_Output = ResultError | ({ status: 'OK' } & BundleMetrics) @@ -247,17 +238,14 @@ export type Health_Output = ResultError | { status: 'OK' } export type LinkNPubThroughToken_Input = {rpcName:'LinkNPubThroughToken', req: LinkNPubThroughTokenRequest} export type LinkNPubThroughToken_Output = ResultError | { status: 'OK' } -export type ListAdminInvoiceSwaps_Input = {rpcName:'ListAdminInvoiceSwaps'} -export type ListAdminInvoiceSwaps_Output = ResultError | ({ status: 'OK' } & InvoiceSwapsList) - -export type ListAdminTxSwaps_Input = {rpcName:'ListAdminTxSwaps'} -export type ListAdminTxSwaps_Output = ResultError | ({ status: 'OK' } & TxSwapsList) +export type ListAdminSwaps_Input = {rpcName:'ListAdminSwaps'} +export type ListAdminSwaps_Output = ResultError | ({ status: 'OK' } & SwapsList) export type ListChannels_Input = {rpcName:'ListChannels'} export type ListChannels_Output = ResultError | ({ status: 'OK' } & LndChannels) -export type ListTxSwaps_Input = {rpcName:'ListTxSwaps'} -export type ListTxSwaps_Output = ResultError | ({ status: 'OK' } & TxSwapsList) +export type ListSwaps_Input = {rpcName:'ListSwaps'} +export type ListSwaps_Output = ResultError | ({ status: 'OK' } & SwapsList) export type LndGetInfo_Input = {rpcName:'LndGetInfo', req: LndGetInfoRequest} export type LndGetInfo_Output = ResultError | ({ status: 'OK' } & LndGetInfoResponse) @@ -280,11 +268,8 @@ export type OpenChannel_Output = ResultError | ({ status: 'OK' } & OpenChannelRe export type PayAddress_Input = {rpcName:'PayAddress', req: PayAddressRequest} export type PayAddress_Output = ResultError | ({ status: 'OK' } & PayAddressResponse) -export type PayAdminInvoiceSwap_Input = {rpcName:'PayAdminInvoiceSwap', req: PayAdminInvoiceSwapRequest} -export type PayAdminInvoiceSwap_Output = ResultError | ({ status: 'OK' } & AdminInvoiceSwapResponse) - export type PayAdminTransactionSwap_Input = {rpcName:'PayAdminTransactionSwap', req: PayAdminTransactionSwapRequest} -export type PayAdminTransactionSwap_Output = ResultError | ({ status: 'OK' } & AdminTxSwapResponse) +export type PayAdminTransactionSwap_Output = ResultError | ({ status: 'OK' } & AdminSwapResponse) export type PayAppUserInvoice_Input = {rpcName:'PayAppUserInvoice', req: PayAppUserInvoiceRequest} export type PayAppUserInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse) @@ -295,9 +280,6 @@ export type PayInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResp export type PingSubProcesses_Input = {rpcName:'PingSubProcesses'} export type PingSubProcesses_Output = ResultError | { status: 'OK' } -export type RefundAdminInvoiceSwap_Input = {rpcName:'RefundAdminInvoiceSwap', req: RefundAdminInvoiceSwapRequest} -export type RefundAdminInvoiceSwap_Output = ResultError | ({ status: 'OK' } & AdminInvoiceSwapResponse) - export type RequestNPubLinkingToken_Input = {rpcName:'RequestNPubLinkingToken', req: RequestNPubLinkingTokenRequest} export type RequestNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse) @@ -367,7 +349,6 @@ export type ServerMethods = { AuthorizeManage?: (req: AuthorizeManage_Input & {ctx: UserContext }) => Promise BanDebit?: (req: BanDebit_Input & {ctx: UserContext }) => Promise BanUser?: (req: BanUser_Input & {ctx: AdminContext }) => Promise - BumpTx?: (req: BumpTx_Input & {ctx: AdminContext }) => Promise CloseChannel?: (req: CloseChannel_Input & {ctx: AdminContext }) => Promise CreateOneTimeInviteLink?: (req: CreateOneTimeInviteLink_Input & {ctx: AdminContext }) => Promise DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise @@ -376,13 +357,11 @@ export type ServerMethods = { EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise EnrollMessagingToken?: (req: EnrollMessagingToken_Input & {ctx: UserContext }) => Promise - GetAdminInvoiceSwapQuotes?: (req: GetAdminInvoiceSwapQuotes_Input & {ctx: AdminContext }) => Promise GetAdminTransactionSwapQuotes?: (req: GetAdminTransactionSwapQuotes_Input & {ctx: AdminContext }) => Promise GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise - GetAssetsAndLiabilities?: (req: GetAssetsAndLiabilities_Input & {ctx: AdminContext }) => Promise GetBundleMetrics?: (req: GetBundleMetrics_Input & {ctx: MetricsContext }) => Promise GetDebitAuthorizations?: (req: GetDebitAuthorizations_Input & {ctx: UserContext }) => Promise GetErrorStats?: (req: GetErrorStats_Input & {ctx: MetricsContext }) => Promise @@ -418,22 +397,19 @@ export type ServerMethods = { HandleLnurlWithdraw?: (req: HandleLnurlWithdraw_Input & {ctx: GuestContext }) => Promise Health?: (req: Health_Input & {ctx: GuestContext }) => Promise LinkNPubThroughToken?: (req: LinkNPubThroughToken_Input & {ctx: GuestWithPubContext }) => Promise - ListAdminInvoiceSwaps?: (req: ListAdminInvoiceSwaps_Input & {ctx: AdminContext }) => Promise - ListAdminTxSwaps?: (req: ListAdminTxSwaps_Input & {ctx: AdminContext }) => Promise + ListAdminSwaps?: (req: ListAdminSwaps_Input & {ctx: AdminContext }) => Promise ListChannels?: (req: ListChannels_Input & {ctx: AdminContext }) => Promise - ListTxSwaps?: (req: ListTxSwaps_Input & {ctx: UserContext }) => Promise + ListSwaps?: (req: ListSwaps_Input & {ctx: UserContext }) => Promise LndGetInfo?: (req: LndGetInfo_Input & {ctx: AdminContext }) => Promise NewAddress?: (req: NewAddress_Input & {ctx: UserContext }) => Promise NewInvoice?: (req: NewInvoice_Input & {ctx: UserContext }) => Promise NewProductInvoice?: (req: NewProductInvoice_Input & {ctx: UserContext }) => Promise OpenChannel?: (req: OpenChannel_Input & {ctx: AdminContext }) => Promise PayAddress?: (req: PayAddress_Input & {ctx: UserContext }) => Promise - PayAdminInvoiceSwap?: (req: PayAdminInvoiceSwap_Input & {ctx: AdminContext }) => Promise - PayAdminTransactionSwap?: (req: PayAdminTransactionSwap_Input & {ctx: AdminContext }) => Promise + PayAdminTransactionSwap?: (req: PayAdminTransactionSwap_Input & {ctx: AdminContext }) => Promise PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise PingSubProcesses?: (req: PingSubProcesses_Input & {ctx: MetricsContext }) => Promise - RefundAdminInvoiceSwap?: (req: RefundAdminInvoiceSwap_Input & {ctx: AdminContext }) => Promise RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise ResetDebit?: (req: ResetDebit_Input & {ctx: UserContext }) => Promise ResetManage?: (req: ResetManage_Input & {ctx: UserContext }) => Promise @@ -489,14 +465,6 @@ export const enumCheckSingleMetricType = (e?: SingleMetricType): boolean => { for (const v in SingleMetricType) if (e === v) return true return false } -export enum TrackedOperationType { - ROOT = 'ROOT', - USER = 'USER', -} -export const enumCheckTrackedOperationType = (e?: TrackedOperationType): boolean => { - for (const v in TrackedOperationType) if (e === v) return true - return false -} export enum UserOperationType { INCOMING_INVOICE = 'INCOMING_INVOICE', INCOMING_TX = 'INCOMING_TX', @@ -703,35 +671,17 @@ export const AddProductRequestValidate = (o?: AddProductRequest, opts: AddProduc return null } -export type AdminInvoiceSwapResponse = { - tx_id: string -} -export const AdminInvoiceSwapResponseOptionalFields: [] = [] -export type AdminInvoiceSwapResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - tx_id_CustomCheck?: (v: string) => boolean -} -export const AdminInvoiceSwapResponseValidate = (o?: AdminInvoiceSwapResponse, opts: AdminInvoiceSwapResponseOptions = {}, path: string = 'AdminInvoiceSwapResponse::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - 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 -} - -export type AdminTxSwapResponse = { +export type AdminSwapResponse = { network_fee: number tx_id: string } -export const AdminTxSwapResponseOptionalFields: [] = [] -export type AdminTxSwapResponseOptions = OptionsBaseMessage & { +export const AdminSwapResponseOptionalFields: [] = [] +export type AdminSwapResponseOptions = OptionsBaseMessage & { checkOptionalsAreSet?: [] network_fee_CustomCheck?: (v: number) => boolean tx_id_CustomCheck?: (v: string) => boolean } -export const AdminTxSwapResponseValidate = (o?: AdminTxSwapResponse, opts: AdminTxSwapResponseOptions = {}, path: string = 'AdminTxSwapResponse::root.'): Error | null => { +export const AdminSwapResponseValidate = (o?: AdminSwapResponse, opts: AdminSwapResponseOptions = {}, path: string = 'AdminSwapResponse::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') @@ -945,105 +895,6 @@ export const AppsMetricsRequestValidate = (o?: AppsMetricsRequest, opts: AppsMet return null } -export type AssetOperation = { - amount: number - tracked?: TrackedOperation - ts: number -} -export type AssetOperationOptionalField = 'tracked' -export const AssetOperationOptionalFields: AssetOperationOptionalField[] = ['tracked'] -export type AssetOperationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: AssetOperationOptionalField[] - amount_CustomCheck?: (v: number) => boolean - tracked_Options?: TrackedOperationOptions - ts_CustomCheck?: (v: number) => boolean -} -export const AssetOperationValidate = (o?: AssetOperation, opts: AssetOperationOptions = {}, path: string = 'AssetOperation::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - if (typeof o.tracked === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('tracked')) { - const trackedErr = TrackedOperationValidate(o.tracked, opts.tracked_Options, `${path}.tracked`) - if (trackedErr !== null) return trackedErr - } - - - if (typeof o.ts !== 'number') return new Error(`${path}.ts: is not a number`) - if (opts.ts_CustomCheck && !opts.ts_CustomCheck(o.ts)) return new Error(`${path}.ts: custom check failed`) - - return null -} - -export type AssetsAndLiabilities = { - liquidity_providers: LiquidityAssetProvider[] - lnds: LndAssetProvider[] - users_balance: number -} -export const AssetsAndLiabilitiesOptionalFields: [] = [] -export type AssetsAndLiabilitiesOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - liquidity_providers_ItemOptions?: LiquidityAssetProviderOptions - liquidity_providers_CustomCheck?: (v: LiquidityAssetProvider[]) => boolean - lnds_ItemOptions?: LndAssetProviderOptions - lnds_CustomCheck?: (v: LndAssetProvider[]) => boolean - users_balance_CustomCheck?: (v: number) => boolean -} -export const AssetsAndLiabilitiesValidate = (o?: AssetsAndLiabilities, opts: AssetsAndLiabilitiesOptions = {}, path: string = 'AssetsAndLiabilities::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.liquidity_providers)) return new Error(`${path}.liquidity_providers: is not an array`) - for (let index = 0; index < o.liquidity_providers.length; index++) { - const liquidity_providersErr = LiquidityAssetProviderValidate(o.liquidity_providers[index], opts.liquidity_providers_ItemOptions, `${path}.liquidity_providers[${index}]`) - if (liquidity_providersErr !== null) return liquidity_providersErr - } - if (opts.liquidity_providers_CustomCheck && !opts.liquidity_providers_CustomCheck(o.liquidity_providers)) return new Error(`${path}.liquidity_providers: custom check failed`) - - if (!Array.isArray(o.lnds)) return new Error(`${path}.lnds: is not an array`) - for (let index = 0; index < o.lnds.length; index++) { - const lndsErr = LndAssetProviderValidate(o.lnds[index], opts.lnds_ItemOptions, `${path}.lnds[${index}]`) - if (lndsErr !== null) return lndsErr - } - if (opts.lnds_CustomCheck && !opts.lnds_CustomCheck(o.lnds)) return new Error(`${path}.lnds: custom check failed`) - - if (typeof o.users_balance !== 'number') return new Error(`${path}.users_balance: is not a number`) - if (opts.users_balance_CustomCheck && !opts.users_balance_CustomCheck(o.users_balance)) return new Error(`${path}.users_balance: custom check failed`) - - return null -} - -export type AssetsAndLiabilitiesReq = { - limit_invoices?: number - limit_payments?: number - limit_providers?: number -} -export type AssetsAndLiabilitiesReqOptionalField = 'limit_invoices' | 'limit_payments' | 'limit_providers' -export const AssetsAndLiabilitiesReqOptionalFields: AssetsAndLiabilitiesReqOptionalField[] = ['limit_invoices', 'limit_payments', 'limit_providers'] -export type AssetsAndLiabilitiesReqOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: AssetsAndLiabilitiesReqOptionalField[] - limit_invoices_CustomCheck?: (v?: number) => boolean - limit_payments_CustomCheck?: (v?: number) => boolean - limit_providers_CustomCheck?: (v?: number) => boolean -} -export const AssetsAndLiabilitiesReqValidate = (o?: AssetsAndLiabilitiesReq, opts: AssetsAndLiabilitiesReqOptions = {}, path: string = 'AssetsAndLiabilitiesReq::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if ((o.limit_invoices || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('limit_invoices')) && typeof o.limit_invoices !== 'number') return new Error(`${path}.limit_invoices: is not a number`) - if (opts.limit_invoices_CustomCheck && !opts.limit_invoices_CustomCheck(o.limit_invoices)) return new Error(`${path}.limit_invoices: custom check failed`) - - if ((o.limit_payments || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('limit_payments')) && typeof o.limit_payments !== 'number') return new Error(`${path}.limit_payments: is not a number`) - if (opts.limit_payments_CustomCheck && !opts.limit_payments_CustomCheck(o.limit_payments)) return new Error(`${path}.limit_payments: custom check failed`) - - if ((o.limit_providers || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('limit_providers')) && typeof o.limit_providers !== 'number') return new Error(`${path}.limit_providers: is not a number`) - if (opts.limit_providers_CustomCheck && !opts.limit_providers_CustomCheck(o.limit_providers)) return new Error(`${path}.limit_providers: custom check failed`) - - return null -} - export type AuthApp = { app: Application auth_token: string @@ -1213,34 +1064,6 @@ export const BeaconDataValidate = (o?: BeaconData, opts: BeaconDataOptions = {}, return null } -export type BumpTx = { - output_index: number - sat_per_vbyte: number - txid: string -} -export const BumpTxOptionalFields: [] = [] -export type BumpTxOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - output_index_CustomCheck?: (v: number) => boolean - sat_per_vbyte_CustomCheck?: (v: number) => boolean - txid_CustomCheck?: (v: string) => boolean -} -export const BumpTxValidate = (o?: BumpTx, opts: BumpTxOptions = {}, path: string = 'BumpTx::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.output_index !== 'number') return new Error(`${path}.output_index: is not a number`) - if (opts.output_index_CustomCheck && !opts.output_index_CustomCheck(o.output_index)) return new Error(`${path}.output_index: custom check failed`) - - if (typeof o.sat_per_vbyte !== 'number') return new Error(`${path}.sat_per_vbyte: is not a number`) - if (opts.sat_per_vbyte_CustomCheck && !opts.sat_per_vbyte_CustomCheck(o.sat_per_vbyte)) return new Error(`${path}.sat_per_vbyte: custom check failed`) - - if (typeof o.txid !== 'string') return new Error(`${path}.txid: is not a string`) - if (opts.txid_CustomCheck && !opts.txid_CustomCheck(o.txid)) return new Error(`${path}.txid: custom check failed`) - - return null -} - export type BundleData = { available_chunks: number[] base_64_data: string[] @@ -2265,186 +2088,6 @@ export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, pa return null } -export type InvoiceSwapOperation = { - completed_at_unix?: number - failure_reason?: string - operation_payment?: UserOperation - quote: InvoiceSwapQuote -} -export type InvoiceSwapOperationOptionalField = 'completed_at_unix' | 'failure_reason' | 'operation_payment' -export const InvoiceSwapOperationOptionalFields: InvoiceSwapOperationOptionalField[] = ['completed_at_unix', 'failure_reason', 'operation_payment'] -export type InvoiceSwapOperationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: InvoiceSwapOperationOptionalField[] - completed_at_unix_CustomCheck?: (v?: number) => boolean - failure_reason_CustomCheck?: (v?: string) => boolean - operation_payment_Options?: UserOperationOptions - quote_Options?: InvoiceSwapQuoteOptions -} -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 (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 (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`) - - 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`) - if (operation_paymentErr !== null) return operation_paymentErr - } - - - const quoteErr = InvoiceSwapQuoteValidate(o.quote, opts.quote_Options, `${path}.quote`) - if (quoteErr !== null) return quoteErr - - - return null -} - -export type InvoiceSwapQuote = { - address: string - chain_fee_sats: number - expires_at_block_height: number - invoice: string - invoice_amount_sats: number - paid_at_unix: number - service_fee_sats: number - service_url: string - swap_fee_sats: number - swap_operation_id: string - transaction_amount_sats: number - tx_id: string -} -export const InvoiceSwapQuoteOptionalFields: [] = [] -export type InvoiceSwapQuoteOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - address_CustomCheck?: (v: string) => boolean - chain_fee_sats_CustomCheck?: (v: number) => boolean - expires_at_block_height_CustomCheck?: (v: number) => boolean - invoice_CustomCheck?: (v: string) => boolean - invoice_amount_sats_CustomCheck?: (v: number) => boolean - paid_at_unix_CustomCheck?: (v: number) => boolean - service_fee_sats_CustomCheck?: (v: number) => boolean - service_url_CustomCheck?: (v: string) => boolean - swap_fee_sats_CustomCheck?: (v: number) => boolean - swap_operation_id_CustomCheck?: (v: string) => boolean - transaction_amount_sats_CustomCheck?: (v: number) => boolean - tx_id_CustomCheck?: (v: string) => boolean -} -export const InvoiceSwapQuoteValidate = (o?: InvoiceSwapQuote, opts: InvoiceSwapQuoteOptions = {}, path: string = 'InvoiceSwapQuote::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.address !== 'string') return new Error(`${path}.address: is not a string`) - if (opts.address_CustomCheck && !opts.address_CustomCheck(o.address)) return new Error(`${path}.address: custom check failed`) - - 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 (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 (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 (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 (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 (typeof o.service_url !== 'string') return new Error(`${path}.service_url: is not a string`) - if (opts.service_url_CustomCheck && !opts.service_url_CustomCheck(o.service_url)) return new Error(`${path}.service_url: custom check failed`) - - if (typeof o.swap_fee_sats !== 'number') return new Error(`${path}.swap_fee_sats: is not a number`) - if (opts.swap_fee_sats_CustomCheck && !opts.swap_fee_sats_CustomCheck(o.swap_fee_sats)) return new Error(`${path}.swap_fee_sats: custom check failed`) - - if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`) - 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 (typeof o.transaction_amount_sats !== 'number') return new Error(`${path}.transaction_amount_sats: is not a number`) - if (opts.transaction_amount_sats_CustomCheck && !opts.transaction_amount_sats_CustomCheck(o.transaction_amount_sats)) return new Error(`${path}.transaction_amount_sats: custom check failed`) - - 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 -} - -export type InvoiceSwapQuoteList = { - quotes: InvoiceSwapQuote[] -} -export const InvoiceSwapQuoteListOptionalFields: [] = [] -export type InvoiceSwapQuoteListOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - quotes_ItemOptions?: InvoiceSwapQuoteOptions - quotes_CustomCheck?: (v: InvoiceSwapQuote[]) => boolean -} -export const InvoiceSwapQuoteListValidate = (o?: InvoiceSwapQuoteList, opts: InvoiceSwapQuoteListOptions = {}, path: string = 'InvoiceSwapQuoteList::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 (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`) - for (let index = 0; index < o.quotes.length; index++) { - 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`) - - return null -} - -export type InvoiceSwapRequest = { - amount_sats: number -} -export const InvoiceSwapRequestOptionalFields: [] = [] -export type InvoiceSwapRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - amount_sats_CustomCheck?: (v: number) => boolean -} -export const InvoiceSwapRequestValidate = (o?: InvoiceSwapRequest, opts: InvoiceSwapRequestOptions = {}, path: string = 'InvoiceSwapRequest::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.amount_sats !== 'number') return new Error(`${path}.amount_sats: is not a number`) - if (opts.amount_sats_CustomCheck && !opts.amount_sats_CustomCheck(o.amount_sats)) return new Error(`${path}.amount_sats: custom check failed`) - - return null -} - -export type InvoiceSwapsList = { - current_block_height: number - swaps: InvoiceSwapOperation[] -} -export const InvoiceSwapsListOptionalFields: [] = [] -export type InvoiceSwapsListOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - current_block_height_CustomCheck?: (v: number) => boolean - swaps_ItemOptions?: InvoiceSwapOperationOptions - swaps_CustomCheck?: (v: InvoiceSwapOperation[]) => boolean -} -export const InvoiceSwapsListValidate = (o?: InvoiceSwapsList, opts: InvoiceSwapsListOptions = {}, path: string = 'InvoiceSwapsList::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.current_block_height !== 'number') return new Error(`${path}.current_block_height: is not a number`) - 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`) - - if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`) - for (let index = 0; index < o.swaps.length; index++) { - const swapsErr = InvoiceSwapOperationValidate(o.swaps[index], opts.swaps_ItemOptions, `${path}.swaps[${index}]`) - if (swapsErr !== null) return swapsErr - } - if (opts.swaps_CustomCheck && !opts.swaps_CustomCheck(o.swaps)) return new Error(`${path}.swaps: custom check failed`) - - return null -} - export type LatestBundleMetricReq = { limit?: number } @@ -2501,33 +2144,6 @@ export const LinkNPubThroughTokenRequestValidate = (o?: LinkNPubThroughTokenRequ return null } -export type LiquidityAssetProvider = { - pubkey: string - tracked?: TrackedLiquidityProvider -} -export type LiquidityAssetProviderOptionalField = 'tracked' -export const LiquidityAssetProviderOptionalFields: LiquidityAssetProviderOptionalField[] = ['tracked'] -export type LiquidityAssetProviderOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: LiquidityAssetProviderOptionalField[] - pubkey_CustomCheck?: (v: string) => boolean - tracked_Options?: TrackedLiquidityProviderOptions -} -export const LiquidityAssetProviderValidate = (o?: LiquidityAssetProvider, opts: LiquidityAssetProviderOptions = {}, path: string = 'LiquidityAssetProvider::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.pubkey !== 'string') return new Error(`${path}.pubkey: is not a string`) - if (opts.pubkey_CustomCheck && !opts.pubkey_CustomCheck(o.pubkey)) return new Error(`${path}.pubkey: custom check failed`) - - if (typeof o.tracked === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('tracked')) { - const trackedErr = TrackedLiquidityProviderValidate(o.tracked, opts.tracked_Options, `${path}.tracked`) - if (trackedErr !== null) return trackedErr - } - - - return null -} - export type LiveDebitRequest = { debit: LiveDebitRequest_debit npub: string @@ -2604,33 +2220,6 @@ export const LiveUserOperationValidate = (o?: LiveUserOperation, opts: LiveUserO return null } -export type LndAssetProvider = { - pubkey: string - tracked?: TrackedLndProvider -} -export type LndAssetProviderOptionalField = 'tracked' -export const LndAssetProviderOptionalFields: LndAssetProviderOptionalField[] = ['tracked'] -export type LndAssetProviderOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: LndAssetProviderOptionalField[] - pubkey_CustomCheck?: (v: string) => boolean - tracked_Options?: TrackedLndProviderOptions -} -export const LndAssetProviderValidate = (o?: LndAssetProvider, opts: LndAssetProviderOptions = {}, path: string = 'LndAssetProvider::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.pubkey !== 'string') return new Error(`${path}.pubkey: is not a string`) - if (opts.pubkey_CustomCheck && !opts.pubkey_CustomCheck(o.pubkey)) return new Error(`${path}.pubkey: custom check failed`) - - if (typeof o.tracked === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('tracked')) { - const trackedErr = TrackedLndProviderValidate(o.tracked, opts.tracked_Options, `${path}.tracked`) - if (trackedErr !== null) return trackedErr - } - - - return null -} - export type LndChannels = { open_channels: OpenChannel[] } @@ -3719,35 +3308,6 @@ export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddr return null } -export type PayAdminInvoiceSwapRequest = { - no_claim?: boolean - sat_per_v_byte: number - swap_operation_id: string -} -export type PayAdminInvoiceSwapRequestOptionalField = 'no_claim' -export const PayAdminInvoiceSwapRequestOptionalFields: PayAdminInvoiceSwapRequestOptionalField[] = ['no_claim'] -export type PayAdminInvoiceSwapRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: PayAdminInvoiceSwapRequestOptionalField[] - no_claim_CustomCheck?: (v?: boolean) => boolean - sat_per_v_byte_CustomCheck?: (v: number) => boolean - swap_operation_id_CustomCheck?: (v: string) => boolean -} -export const PayAdminInvoiceSwapRequestValidate = (o?: PayAdminInvoiceSwapRequest, opts: PayAdminInvoiceSwapRequestOptions = {}, path: string = 'PayAdminInvoiceSwapRequest::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if ((o.no_claim || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('no_claim')) && typeof o.no_claim !== 'boolean') return new Error(`${path}.no_claim: is not a boolean`) - if (opts.no_claim_CustomCheck && !opts.no_claim_CustomCheck(o.no_claim)) return new Error(`${path}.no_claim: custom check failed`) - - if (typeof o.sat_per_v_byte !== 'number') return new Error(`${path}.sat_per_v_byte: is not a number`) - if (opts.sat_per_v_byte_CustomCheck && !opts.sat_per_v_byte_CustomCheck(o.sat_per_v_byte)) return new Error(`${path}.sat_per_v_byte: custom check failed`) - - if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`) - 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`) - - return null -} - export type PayAdminTransactionSwapRequest = { address: string swap_operation_id: string @@ -4040,76 +3600,6 @@ export const ProvidersDisruptionValidate = (o?: ProvidersDisruption, opts: Provi return null } -export type PushNotificationEnvelope = { - app_npub_hex: string - encrypted_payload: string - topic_id: string -} -export const PushNotificationEnvelopeOptionalFields: [] = [] -export type PushNotificationEnvelopeOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - app_npub_hex_CustomCheck?: (v: string) => boolean - encrypted_payload_CustomCheck?: (v: string) => boolean - topic_id_CustomCheck?: (v: string) => boolean -} -export const PushNotificationEnvelopeValidate = (o?: PushNotificationEnvelope, opts: PushNotificationEnvelopeOptions = {}, path: string = 'PushNotificationEnvelope::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.app_npub_hex !== 'string') return new Error(`${path}.app_npub_hex: is not a string`) - if (opts.app_npub_hex_CustomCheck && !opts.app_npub_hex_CustomCheck(o.app_npub_hex)) return new Error(`${path}.app_npub_hex: custom check failed`) - - if (typeof o.encrypted_payload !== 'string') return new Error(`${path}.encrypted_payload: is not a string`) - if (opts.encrypted_payload_CustomCheck && !opts.encrypted_payload_CustomCheck(o.encrypted_payload)) return new Error(`${path}.encrypted_payload: custom check failed`) - - if (typeof o.topic_id !== 'string') return new Error(`${path}.topic_id: is not a string`) - if (opts.topic_id_CustomCheck && !opts.topic_id_CustomCheck(o.topic_id)) return new Error(`${path}.topic_id: custom check failed`) - - return null -} - -export type PushNotificationPayload = { - data: PushNotificationPayload_data -} -export const PushNotificationPayloadOptionalFields: [] = [] -export type PushNotificationPayloadOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - data_Options?: PushNotificationPayload_dataOptions -} -export const PushNotificationPayloadValidate = (o?: PushNotificationPayload, opts: PushNotificationPayloadOptions = {}, path: string = 'PushNotificationPayload::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - const dataErr = PushNotificationPayload_dataValidate(o.data, opts.data_Options, `${path}.data`) - if (dataErr !== null) return dataErr - - - return null -} - -export type RefundAdminInvoiceSwapRequest = { - sat_per_v_byte: number - swap_operation_id: string -} -export const RefundAdminInvoiceSwapRequestOptionalFields: [] = [] -export type RefundAdminInvoiceSwapRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - sat_per_v_byte_CustomCheck?: (v: number) => boolean - swap_operation_id_CustomCheck?: (v: string) => boolean -} -export const RefundAdminInvoiceSwapRequestValidate = (o?: RefundAdminInvoiceSwapRequest, opts: RefundAdminInvoiceSwapRequestOptions = {}, path: string = 'RefundAdminInvoiceSwapRequest::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.sat_per_v_byte !== 'number') return new Error(`${path}.sat_per_v_byte: is not a number`) - if (opts.sat_per_v_byte_CustomCheck && !opts.sat_per_v_byte_CustomCheck(o.sat_per_v_byte)) return new Error(`${path}.sat_per_v_byte: custom check failed`) - - if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`) - 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`) - - return null -} - export type RelaysMigration = { relays: string[] } @@ -4427,146 +3917,79 @@ export const SingleMetricReqValidate = (o?: SingleMetricReq, opts: SingleMetricR return null } -export type TrackedLiquidityProvider = { - balance: number - invoices: AssetOperation[] - payments: AssetOperation[] +export type SwapOperation = { + address_paid: string + failure_reason?: string + operation_payment?: UserOperation + swap_operation_id: string } -export const TrackedLiquidityProviderOptionalFields: [] = [] -export type TrackedLiquidityProviderOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - balance_CustomCheck?: (v: number) => boolean - invoices_ItemOptions?: AssetOperationOptions - invoices_CustomCheck?: (v: AssetOperation[]) => boolean - payments_ItemOptions?: AssetOperationOptions - payments_CustomCheck?: (v: AssetOperation[]) => boolean +export type SwapOperationOptionalField = 'failure_reason' | 'operation_payment' +export const SwapOperationOptionalFields: SwapOperationOptionalField[] = ['failure_reason', 'operation_payment'] +export type SwapOperationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: SwapOperationOptionalField[] + address_paid_CustomCheck?: (v: string) => boolean + failure_reason_CustomCheck?: (v?: string) => boolean + operation_payment_Options?: UserOperationOptions + swap_operation_id_CustomCheck?: (v: string) => boolean } -export const TrackedLiquidityProviderValidate = (o?: TrackedLiquidityProvider, opts: TrackedLiquidityProviderOptions = {}, path: string = 'TrackedLiquidityProvider::root.'): Error | null => { +export const SwapOperationValidate = (o?: SwapOperation, opts: SwapOperationOptions = {}, path: string = 'SwapOperation::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) - if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) + if (typeof o.address_paid !== 'string') return new Error(`${path}.address_paid: is not a string`) + if (opts.address_paid_CustomCheck && !opts.address_paid_CustomCheck(o.address_paid)) return new Error(`${path}.address_paid: custom check failed`) - if (!Array.isArray(o.invoices)) return new Error(`${path}.invoices: is not an array`) - for (let index = 0; index < o.invoices.length; index++) { - const invoicesErr = AssetOperationValidate(o.invoices[index], opts.invoices_ItemOptions, `${path}.invoices[${index}]`) - if (invoicesErr !== null) return invoicesErr - } - if (opts.invoices_CustomCheck && !opts.invoices_CustomCheck(o.invoices)) return new Error(`${path}.invoices: 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 (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`) - if (!Array.isArray(o.payments)) return new Error(`${path}.payments: is not an array`) - for (let index = 0; index < o.payments.length; index++) { - const paymentsErr = AssetOperationValidate(o.payments[index], opts.payments_ItemOptions, `${path}.payments[${index}]`) - if (paymentsErr !== null) return paymentsErr + 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`) + if (operation_paymentErr !== null) return operation_paymentErr } - if (opts.payments_CustomCheck && !opts.payments_CustomCheck(o.payments)) return new Error(`${path}.payments: custom check failed`) + + + if (typeof o.swap_operation_id !== 'string') return new Error(`${path}.swap_operation_id: is not a string`) + 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`) return null } -export type TrackedLndProvider = { - channels_balance: number - confirmed_balance: number - incoming_tx: AssetOperation[] - invoices: AssetOperation[] - outgoing_tx: AssetOperation[] - payments: AssetOperation[] - unconfirmed_balance: number +export type SwapsList = { + quotes: TransactionSwapQuote[] + swaps: SwapOperation[] } -export const TrackedLndProviderOptionalFields: [] = [] -export type TrackedLndProviderOptions = OptionsBaseMessage & { +export const SwapsListOptionalFields: [] = [] +export type SwapsListOptions = OptionsBaseMessage & { checkOptionalsAreSet?: [] - channels_balance_CustomCheck?: (v: number) => boolean - confirmed_balance_CustomCheck?: (v: number) => boolean - incoming_tx_ItemOptions?: AssetOperationOptions - incoming_tx_CustomCheck?: (v: AssetOperation[]) => boolean - invoices_ItemOptions?: AssetOperationOptions - invoices_CustomCheck?: (v: AssetOperation[]) => boolean - outgoing_tx_ItemOptions?: AssetOperationOptions - outgoing_tx_CustomCheck?: (v: AssetOperation[]) => boolean - payments_ItemOptions?: AssetOperationOptions - payments_CustomCheck?: (v: AssetOperation[]) => boolean - unconfirmed_balance_CustomCheck?: (v: number) => boolean + quotes_ItemOptions?: TransactionSwapQuoteOptions + quotes_CustomCheck?: (v: TransactionSwapQuote[]) => boolean + swaps_ItemOptions?: SwapOperationOptions + swaps_CustomCheck?: (v: SwapOperation[]) => boolean } -export const TrackedLndProviderValidate = (o?: TrackedLndProvider, opts: TrackedLndProviderOptions = {}, path: string = 'TrackedLndProvider::root.'): Error | null => { +export const SwapsListValidate = (o?: SwapsList, opts: SwapsListOptions = {}, path: string = 'SwapsList::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - if (typeof o.channels_balance !== 'number') return new Error(`${path}.channels_balance: is not a number`) - if (opts.channels_balance_CustomCheck && !opts.channels_balance_CustomCheck(o.channels_balance)) return new Error(`${path}.channels_balance: custom check failed`) - - if (typeof o.confirmed_balance !== 'number') return new Error(`${path}.confirmed_balance: is not a number`) - if (opts.confirmed_balance_CustomCheck && !opts.confirmed_balance_CustomCheck(o.confirmed_balance)) return new Error(`${path}.confirmed_balance: custom check failed`) - - if (!Array.isArray(o.incoming_tx)) return new Error(`${path}.incoming_tx: is not an array`) - for (let index = 0; index < o.incoming_tx.length; index++) { - const incoming_txErr = AssetOperationValidate(o.incoming_tx[index], opts.incoming_tx_ItemOptions, `${path}.incoming_tx[${index}]`) - if (incoming_txErr !== null) return incoming_txErr + if (!Array.isArray(o.quotes)) return new Error(`${path}.quotes: is not an array`) + for (let index = 0; index < o.quotes.length; index++) { + const quotesErr = TransactionSwapQuoteValidate(o.quotes[index], opts.quotes_ItemOptions, `${path}.quotes[${index}]`) + if (quotesErr !== null) return quotesErr } - if (opts.incoming_tx_CustomCheck && !opts.incoming_tx_CustomCheck(o.incoming_tx)) return new Error(`${path}.incoming_tx: custom check failed`) + if (opts.quotes_CustomCheck && !opts.quotes_CustomCheck(o.quotes)) return new Error(`${path}.quotes: custom check failed`) - if (!Array.isArray(o.invoices)) return new Error(`${path}.invoices: is not an array`) - for (let index = 0; index < o.invoices.length; index++) { - const invoicesErr = AssetOperationValidate(o.invoices[index], opts.invoices_ItemOptions, `${path}.invoices[${index}]`) - if (invoicesErr !== null) return invoicesErr + if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`) + for (let index = 0; index < o.swaps.length; index++) { + const swapsErr = SwapOperationValidate(o.swaps[index], opts.swaps_ItemOptions, `${path}.swaps[${index}]`) + if (swapsErr !== null) return swapsErr } - if (opts.invoices_CustomCheck && !opts.invoices_CustomCheck(o.invoices)) return new Error(`${path}.invoices: custom check failed`) - - if (!Array.isArray(o.outgoing_tx)) return new Error(`${path}.outgoing_tx: is not an array`) - for (let index = 0; index < o.outgoing_tx.length; index++) { - const outgoing_txErr = AssetOperationValidate(o.outgoing_tx[index], opts.outgoing_tx_ItemOptions, `${path}.outgoing_tx[${index}]`) - if (outgoing_txErr !== null) return outgoing_txErr - } - if (opts.outgoing_tx_CustomCheck && !opts.outgoing_tx_CustomCheck(o.outgoing_tx)) return new Error(`${path}.outgoing_tx: custom check failed`) - - if (!Array.isArray(o.payments)) return new Error(`${path}.payments: is not an array`) - for (let index = 0; index < o.payments.length; index++) { - const paymentsErr = AssetOperationValidate(o.payments[index], opts.payments_ItemOptions, `${path}.payments[${index}]`) - if (paymentsErr !== null) return paymentsErr - } - if (opts.payments_CustomCheck && !opts.payments_CustomCheck(o.payments)) return new Error(`${path}.payments: custom check failed`) - - if (typeof o.unconfirmed_balance !== 'number') return new Error(`${path}.unconfirmed_balance: is not a number`) - if (opts.unconfirmed_balance_CustomCheck && !opts.unconfirmed_balance_CustomCheck(o.unconfirmed_balance)) return new Error(`${path}.unconfirmed_balance: custom check failed`) - - return null -} - -export type TrackedOperation = { - amount: number - ts: number - type: TrackedOperationType -} -export const TrackedOperationOptionalFields: [] = [] -export type TrackedOperationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - amount_CustomCheck?: (v: number) => boolean - ts_CustomCheck?: (v: number) => boolean - type_CustomCheck?: (v: TrackedOperationType) => boolean -} -export const TrackedOperationValidate = (o?: TrackedOperation, opts: TrackedOperationOptions = {}, path: string = 'TrackedOperation::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - if (typeof o.ts !== 'number') return new Error(`${path}.ts: is not a number`) - if (opts.ts_CustomCheck && !opts.ts_CustomCheck(o.ts)) return new Error(`${path}.ts: custom check failed`) - - if (!enumCheckTrackedOperationType(o.type)) return new Error(`${path}.type: is not a valid TrackedOperationType`) - if (opts.type_CustomCheck && !opts.type_CustomCheck(o.type)) return new Error(`${path}.type: custom check failed`) + if (opts.swaps_CustomCheck && !opts.swaps_CustomCheck(o.swaps)) return new Error(`${path}.swaps: custom check failed`) return null } export type TransactionSwapQuote = { chain_fee_sats: number - completed_at_unix: number - expires_at_block_height: number invoice_amount_sats: number - paid_at_unix: number service_fee_sats: number service_url: string swap_fee_sats: number @@ -4577,10 +4000,7 @@ export const TransactionSwapQuoteOptionalFields: [] = [] export type TransactionSwapQuoteOptions = OptionsBaseMessage & { checkOptionalsAreSet?: [] chain_fee_sats_CustomCheck?: (v: number) => boolean - completed_at_unix_CustomCheck?: (v: number) => boolean - expires_at_block_height_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_url_CustomCheck?: (v: string) => boolean swap_fee_sats_CustomCheck?: (v: number) => boolean @@ -4594,18 +4014,9 @@ export const TransactionSwapQuoteValidate = (o?: TransactionSwapQuote, opts: Tra 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 (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 (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_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 (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 (opts.service_fee_sats_CustomCheck && !opts.service_fee_sats_CustomCheck(o.service_fee_sats)) return new Error(`${path}.service_fee_sats: custom check failed`) @@ -4665,72 +4076,6 @@ export const TransactionSwapRequestValidate = (o?: TransactionSwapRequest, opts: return null } -export type TxSwapOperation = { - address_paid?: string - failure_reason?: string - operation_payment?: UserOperation - quote: TransactionSwapQuote - tx_id?: string -} -export type TxSwapOperationOptionalField = 'address_paid' | 'failure_reason' | 'operation_payment' | 'tx_id' -export const TxSwapOperationOptionalFields: TxSwapOperationOptionalField[] = ['address_paid', 'failure_reason', 'operation_payment', 'tx_id'] -export type TxSwapOperationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: TxSwapOperationOptionalField[] - address_paid_CustomCheck?: (v?: string) => boolean - failure_reason_CustomCheck?: (v?: string) => boolean - operation_payment_Options?: UserOperationOptions - quote_Options?: TransactionSwapQuoteOptions - tx_id_CustomCheck?: (v?: string) => boolean -} -export const TxSwapOperationValidate = (o?: TxSwapOperation, opts: TxSwapOperationOptions = {}, path: string = 'TxSwapOperation::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if ((o.address_paid || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('address_paid')) && typeof o.address_paid !== 'string') return new Error(`${path}.address_paid: is not a string`) - if (opts.address_paid_CustomCheck && !opts.address_paid_CustomCheck(o.address_paid)) return new Error(`${path}.address_paid: 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 (opts.failure_reason_CustomCheck && !opts.failure_reason_CustomCheck(o.failure_reason)) return new Error(`${path}.failure_reason: custom check failed`) - - 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`) - if (operation_paymentErr !== null) return operation_paymentErr - } - - - const quoteErr = TransactionSwapQuoteValidate(o.quote, opts.quote_Options, `${path}.quote`) - if (quoteErr !== null) return quoteErr - - - if ((o.tx_id || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('tx_id')) && 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 -} - -export type TxSwapsList = { - swaps: TxSwapOperation[] -} -export const TxSwapsListOptionalFields: [] = [] -export type TxSwapsListOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - swaps_ItemOptions?: TxSwapOperationOptions - swaps_CustomCheck?: (v: TxSwapOperation[]) => boolean -} -export const TxSwapsListValidate = (o?: TxSwapsList, opts: TxSwapsListOptions = {}, path: string = 'TxSwapsList::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 (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.swaps)) return new Error(`${path}.swaps: is not an array`) - for (let index = 0; index < o.swaps.length; index++) { - const swapsErr = TxSwapOperationValidate(o.swaps[index], opts.swaps_ItemOptions, `${path}.swaps[${index}]`) - if (swapsErr !== null) return swapsErr - } - if (opts.swaps_CustomCheck && !opts.swaps_CustomCheck(o.swaps)) return new Error(`${path}.swaps: custom check failed`) - - return null -} - export type UpdateChannelPolicyRequest = { policy: ChannelPolicy update: UpdateChannelPolicyRequest_update @@ -4928,7 +4273,6 @@ export type UserInfo = { nmanage: string noffer: string service_fee_bps: number - topic_id: string userId: string user_identifier: string } @@ -4945,7 +4289,6 @@ export type UserInfoOptions = OptionsBaseMessage & { nmanage_CustomCheck?: (v: string) => boolean noffer_CustomCheck?: (v: string) => boolean service_fee_bps_CustomCheck?: (v: number) => boolean - topic_id_CustomCheck?: (v: string) => boolean userId_CustomCheck?: (v: string) => boolean user_identifier_CustomCheck?: (v: string) => boolean } @@ -4983,9 +4326,6 @@ export const UserInfoValidate = (o?: UserInfo, opts: UserInfoOptions = {}, path: if (typeof o.service_fee_bps !== 'number') return new Error(`${path}.service_fee_bps: is not a number`) if (opts.service_fee_bps_CustomCheck && !opts.service_fee_bps_CustomCheck(o.service_fee_bps)) return new Error(`${path}.service_fee_bps: custom check failed`) - if (typeof o.topic_id !== 'string') return new Error(`${path}.topic_id: is not a string`) - if (opts.topic_id_CustomCheck && !opts.topic_id_CustomCheck(o.topic_id)) return new Error(`${path}.topic_id: custom check failed`) - if (typeof o.userId !== 'string') return new Error(`${path}.userId: is not a string`) if (opts.userId_CustomCheck && !opts.userId_CustomCheck(o.userId)) return new Error(`${path}.userId: custom check failed`) @@ -5403,43 +4743,6 @@ export const NPubLinking_stateValidate = (o?: NPubLinking_state, opts:NPubLinkin if (unlinkedErr !== null) return unlinkedErr - break - default: - return new Error(path + ': unknown type '+ stringType) - } - return null -} -export enum PushNotificationPayload_data_type { - RECEIVED_OPERATION = 'received_operation', - SENT_OPERATION = 'sent_operation', -} -export const enumCheckPushNotificationPayload_data_type = (e?: PushNotificationPayload_data_type): boolean => { - for (const v in PushNotificationPayload_data_type) if (e === v) return true - return false -} -export type PushNotificationPayload_data = - {type:PushNotificationPayload_data_type.RECEIVED_OPERATION, received_operation:UserOperation}| - {type:PushNotificationPayload_data_type.SENT_OPERATION, sent_operation:UserOperation} - -export type PushNotificationPayload_dataOptions = { - received_operation_Options?: UserOperationOptions - sent_operation_Options?: UserOperationOptions -} -export const PushNotificationPayload_dataValidate = (o?: PushNotificationPayload_data, opts:PushNotificationPayload_dataOptions = {}, path: string = 'PushNotificationPayload_data::root.'): Error | null => { - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - const stringType: string = o.type - switch (o.type) { - case PushNotificationPayload_data_type.RECEIVED_OPERATION: - const received_operationErr = UserOperationValidate(o.received_operation, opts.received_operation_Options, `${path}.received_operation`) - if (received_operationErr !== null) return received_operationErr - - - break - case PushNotificationPayload_data_type.SENT_OPERATION: - const sent_operationErr = UserOperationValidate(o.sent_operation, opts.sent_operation_Options, `${path}.sent_operation`) - if (sent_operationErr !== null) return sent_operationErr - - break default: return new Error(path + ': unknown type '+ stringType) diff --git a/proto/service/methods.proto b/proto/service/methods.proto index 2a54767b..feaf3e97 100644 --- a/proto/service/methods.proto +++ b/proto/service/methods.proto @@ -112,20 +112,6 @@ service LightningPub { option (nostr) = true; }; - rpc GetAssetsAndLiabilities(structs.AssetsAndLiabilitiesReq) returns (structs.AssetsAndLiabilities) { - option (auth_type) = "Admin"; - option (http_method) = "post"; - option (http_route) = "/api/admin/assets/liabilities"; - option (nostr) = true; - }; - - rpc BumpTx(structs.BumpTx) returns (structs.Empty) { - option (auth_type) = "Admin"; - option (http_method) = "post"; - option (http_route) = "/api/admin/tx/bump"; - option (nostr) = true; - }; - rpc AddApp(structs.AddAppRequest) returns (structs.AuthApp) { option (auth_type) = "Admin"; option (http_method) = "post"; @@ -189,34 +175,6 @@ service LightningPub { option (nostr) = true; } - rpc GetAdminInvoiceSwapQuotes(structs.InvoiceSwapRequest) returns (structs.InvoiceSwapQuoteList) { - option (auth_type) = "Admin"; - option (http_method) = "post"; - option (http_route) = "/api/admin/swap/invoice/quote"; - option (nostr) = true; - } - - rpc ListAdminInvoiceSwaps(structs.Empty) returns (structs.InvoiceSwapsList) { - option (auth_type) = "Admin"; - option (http_method) = "post"; - option (http_route) = "/api/admin/swap/invoice/list"; - option (nostr) = true; - } - - rpc PayAdminInvoiceSwap(structs.PayAdminInvoiceSwapRequest) returns (structs.AdminInvoiceSwapResponse) { - option (auth_type) = "Admin"; - option (http_method) = "post"; - option (http_route) = "/api/admin/swap/invoice/pay"; - option (nostr) = true; - } - - rpc RefundAdminInvoiceSwap(structs.RefundAdminInvoiceSwapRequest) returns (structs.AdminInvoiceSwapResponse) { - option (auth_type) = "Admin"; - option (http_method) = "post"; - option (http_route) = "/api/admin/swap/invoice/refund"; - option (nostr) = true; - } - rpc GetAdminTransactionSwapQuotes(structs.TransactionSwapRequest) returns (structs.TransactionSwapQuoteList) { option (auth_type) = "Admin"; option (http_method) = "post"; @@ -224,17 +182,17 @@ service LightningPub { option (nostr) = true; } - rpc PayAdminTransactionSwap(structs.PayAdminTransactionSwapRequest) returns (structs.AdminTxSwapResponse) { + rpc PayAdminTransactionSwap(structs.PayAdminTransactionSwapRequest) returns (structs.AdminSwapResponse) { option (auth_type) = "Admin"; option (http_method) = "post"; option (http_route) = "/api/admin/swap/transaction/pay"; option (nostr) = true; } - rpc ListAdminTxSwaps(structs.Empty) returns (structs.TxSwapsList) { + rpc ListAdminSwaps(structs.Empty) returns (structs.SwapsList) { option (auth_type) = "Admin"; option (http_method) = "post"; - option (http_route) = "/api/admin/swap/transaction/list"; + option (http_route) = "/api/admin/swap/list"; option (nostr) = true; } @@ -562,14 +520,14 @@ service LightningPub { rpc GetTransactionSwapQuotes(structs.TransactionSwapRequest) returns (structs.TransactionSwapQuoteList){ option (auth_type) = "User"; option (http_method) = "post"; - option (http_route) = "/api/user/swap/transaction/quote"; + option (http_route) = "/api/user/swap/quote"; option (nostr) = true; } - rpc ListTxSwaps(structs.Empty) returns (structs.TxSwapsList){ + rpc ListSwaps(structs.Empty) returns (structs.SwapsList){ option (auth_type) = "User"; option (http_method) = "post"; - option (http_route) = "/api/user/swap/transaction/list"; + option (http_route) = "/api/user/swap/list"; option (nostr) = true; } diff --git a/proto/service/structs.proto b/proto/service/structs.proto index 3d64ef67..00552fdd 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -19,68 +19,6 @@ message EncryptionExchangeRequest { string deviceId = 2; } -message AssetsAndLiabilitiesReq { - optional int64 limit_invoices = 1; - optional int64 limit_payments = 2; - optional int64 limit_providers = 4; -} - -message BumpTx { - string txid = 1; - int64 output_index = 2; - int64 sat_per_vbyte = 3; -} - - -enum TrackedOperationType { - USER = 0; - ROOT = 1; -} - -message TrackedOperation { - int64 ts = 1; - int64 amount = 2; - TrackedOperationType type = 3; -} - -message AssetOperation { - int64 ts = 1; - int64 amount = 2; - optional TrackedOperation tracked = 3; -} - -message TrackedLndProvider { - int64 confirmed_balance = 1; - int64 unconfirmed_balance = 2; - int64 channels_balance = 3; - repeated AssetOperation payments = 4; - repeated AssetOperation invoices = 5; - repeated AssetOperation incoming_tx = 6; - repeated AssetOperation outgoing_tx = 7; -} - -message TrackedLiquidityProvider { - int64 balance = 1; - repeated AssetOperation payments = 2; - repeated AssetOperation invoices = 3; -} - -message LndAssetProvider { - string pubkey = 1; - optional TrackedLndProvider tracked = 2; -} - -message LiquidityAssetProvider { - string pubkey = 1; - optional TrackedLiquidityProvider tracked = 2; -} - -message AssetsAndLiabilities { - int64 users_balance = 1; - repeated LndAssetProvider lnds = 2; - repeated LiquidityAssetProvider liquidity_providers = 3; -} - message UserHealthState { string downtime_reason = 1; } @@ -99,8 +37,6 @@ message ErrorStats { ErrorStat past1m = 5; } - - message MetricsFile { } @@ -605,7 +541,6 @@ message UserInfo{ string callback_url = 10; string bridge_url = 11; string nmanage = 12; - string topic_id = 13; } @@ -898,56 +833,6 @@ message MessagingToken { string firebase_messaging_token = 2; } -message InvoiceSwapRequest { - int64 amount_sats = 1; -} - -message InvoiceSwapQuote { - string swap_operation_id = 1; - string invoice = 2; - int64 invoice_amount_sats = 3; - string address = 4; - int64 transaction_amount_sats = 5; - int64 chain_fee_sats = 6; - int64 service_fee_sats = 7; - string service_url = 8; - int64 swap_fee_sats = 9; - string tx_id = 10; - int64 paid_at_unix = 11; - int64 expires_at_block_height = 12; -} - -message InvoiceSwapQuoteList { - repeated InvoiceSwapQuote quotes = 1; -} - -message InvoiceSwapOperation { - InvoiceSwapQuote quote = 1; - optional UserOperation operation_payment = 2; - optional string failure_reason = 3; - optional int64 completed_at_unix = 6; -} - -message InvoiceSwapsList { - repeated InvoiceSwapOperation swaps = 1; - int64 current_block_height = 3; -} - -message RefundAdminInvoiceSwapRequest { - string swap_operation_id = 1; - int64 sat_per_v_byte = 2; -} - -message PayAdminInvoiceSwapRequest { - string swap_operation_id = 1; - int64 sat_per_v_byte = 2; - optional bool no_claim = 3; -} - -message AdminInvoiceSwapResponse { - string tx_id = 1; -} - message TransactionSwapRequest { int64 transaction_amount_sats = 2; } @@ -966,31 +851,27 @@ message TransactionSwapQuote { int64 chain_fee_sats = 5; int64 service_fee_sats = 7; string service_url = 8; - - int64 expires_at_block_height = 9; - int64 paid_at_unix = 10; - int64 completed_at_unix = 11; } message TransactionSwapQuoteList { repeated TransactionSwapQuote quotes = 1; } -message AdminTxSwapResponse { +message AdminSwapResponse { string tx_id = 1; int64 network_fee = 2; } -message TxSwapOperation { - TransactionSwapQuote quote = 1; +message SwapOperation { + string swap_operation_id = 1; optional UserOperation operation_payment = 2; optional string failure_reason = 3; - optional string address_paid = 4; - optional string tx_id = 5; + string address_paid = 4; } -message TxSwapsList { - repeated TxSwapOperation swaps = 1; +message SwapsList { + repeated SwapOperation swaps = 1; + repeated TransactionSwapQuote quotes = 2; } message CumulativeFees { @@ -1004,19 +885,4 @@ message BeaconData { optional string avatarUrl = 3; optional string nextRelay = 4; optional CumulativeFees fees = 5; -} - - -message PushNotificationEnvelope { - string topic_id = 1; - string app_npub_hex = 2; - string encrypted_payload = 3; // encrypted PushNotificationPayload -} - - -message PushNotificationPayload { - oneof data { - UserOperation received_operation = 1; - UserOperation sent_operation = 2; - } } \ No newline at end of file diff --git a/src/services/helpers/logger.ts b/src/services/helpers/logger.ts index 62a87eac..4d6601c9 100644 --- a/src/services/helpers/logger.ts +++ b/src/services/helpers/logger.ts @@ -1,17 +1,17 @@ import fs from 'fs' export const DEBUG = Symbol("DEBUG") export const ERROR = Symbol("ERROR") -export const INFO = Symbol("INFO") +export const WARN = Symbol("WARN") type LoggerParams = { appName?: string, userId?: string, component?: string } export type PubLogger = (...message: (string | number | object | symbol)[]) => void type Writer = (message: string) => void const logsDir = process.env.LOGS_DIR || "logs" -const logLevel = process.env.LOG_LEVEL || "INFO" +const logLevel = process.env.LOG_LEVEL || "DEBUG" try { fs.mkdirSync(logsDir) } catch { } -if (logLevel !== "DEBUG" && logLevel !== "INFO" && logLevel !== "ERROR") { - throw new Error("Invalid log level " + logLevel + " must be one of (DEBUG, INFO, ERROR)") +if (logLevel !== "DEBUG" && logLevel !== "WARN" && logLevel !== "ERROR") { + throw new Error("Invalid log level " + logLevel + " must be one of (DEBUG, WARN, ERROR)") } const z = (n: number) => n < 10 ? `0${n}` : `${n}` // Sanitize filename to remove invalid characters for filesystem @@ -67,17 +67,19 @@ export const getLogger = (params: LoggerParams): PubLogger => { } message[0] = "DEBUG" break; - case INFO: + case WARN: if (logLevel === "ERROR") { return } - message[0] = "INFO" + message[0] = "WARN" break; case ERROR: message[0] = "ERROR" break; default: - // treats logs without a level as ERROR level, without prefix so it can be found and fixed if needed + if (logLevel !== "DEBUG") { + return + } } const now = new Date() const timestamp = `${now.getFullYear()}-${z(now.getMonth() + 1)}-${z(now.getDate())} ${z(now.getHours())}:${z(now.getMinutes())}:${z(now.getSeconds())}` diff --git a/src/services/lnd/lnd.ts b/src/services/lnd/lnd.ts index eba48f6d..daf7b411 100644 --- a/src/services/lnd/lnd.ts +++ b/src/services/lnd/lnd.ts @@ -15,7 +15,7 @@ import { AddInvoiceReq } from './addInvoiceReq.js'; import { PayInvoiceReq } from './payInvoiceReq.js'; import { SendCoinsReq } from './sendCoinsReq.js'; import { AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice, NewBlockCb, HtlcCb, BalanceInfo, ChannelEventCb } from './settings.js'; -import { ERROR, getLogger, DEBUG, INFO } from '../helpers/logger.js'; +import { ERROR, getLogger } from '../helpers/logger.js'; import { HtlcEvent_EventType } from '../../../proto/lnd/router.js'; import { LiquidityProvider } from '../main/liquidityProvider.js'; import { Utils } from '../helpers/utilsWrapper.js'; @@ -23,7 +23,7 @@ import { TxPointSettings } from '../storage/tlv/stateBundler.js'; import { WalletKitClient } from '../../../proto/lnd/walletkit.client.js'; import SettingsManager from '../main/settingsManager.js'; import { LndNodeSettings, LndSettings } from '../main/settings.js'; -import { ListAddressesResponse, PublishResponse } from '../../../proto/lnd/walletkit.js'; +import { ListAddressesResponse } from '../../../proto/lnd/walletkit.js'; const DeadLineMetadata = (deadline = 10 * 1000) => ({ deadline: Date.now() + deadline }) const deadLndRetrySeconds = 20 @@ -69,7 +69,7 @@ export default class { // Skip LND client initialization if using only liquidity provider if (liquidProvider.getSettings().useOnlyLiquidityProvider) { - this.log(INFO, "USE_ONLY_LIQUIDITY_PROVIDER enabled, skipping LND client initialization") + this.log("USE_ONLY_LIQUIDITY_PROVIDER enabled, skipping LND client initialization") // Create minimal dummy clients - they won't be used but prevent null reference errors // Use insecure credentials directly (can't combine them) const { lndAddr } = this.getSettings().lndNodeSettings @@ -126,13 +126,13 @@ export default class { } async Warmup() { - this.log(INFO, "Warming up LND") // Skip LND warmup if using only liquidity provider if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { - this.log(INFO, "USE_ONLY_LIQUIDITY_PROVIDER enabled, skipping LND warmup") + this.log("USE_ONLY_LIQUIDITY_PROVIDER enabled, skipping LND warmup") this.ready = true return } + // console.log("Warming up LND") this.SubscribeAddressPaid() this.SubscribeInvoicePaid() await this.SubscribeNewBlock() @@ -147,7 +147,7 @@ export default class { this.ready = true res() } catch (err) { - this.log(INFO, "LND is not ready yet, will try again in 1 second") + this.log("LND is not ready yet, will try again in 1 second") if (Date.now() - now > 1000 * 60) { rej(new Error("LND not ready after 1 minute")) } @@ -156,13 +156,6 @@ export default class { }) } - async PublishTransaction(txHex: string): Promise { - const res = await this.walletKit.publishTransaction({ - txHex: Buffer.from(txHex, 'hex'), label: "" - }, DeadLineMetadata()) - return res.response - } - async GetInfo(): Promise { if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { // Return dummy info when bypass is enabled @@ -176,26 +169,27 @@ export default class { uris: [] } } + // console.log("Getting info") const res = await this.lightning.getInfo({}, DeadLineMetadata()) return res.response } async ListPendingChannels(): Promise { - this.log(DEBUG, "Listing pending channels") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return { pendingOpenChannels: [], pendingClosingChannels: [], pendingForceClosingChannels: [], waitingCloseChannels: [], totalLimboBalance: 0n } } + // console.log("Listing pending channels") const res = await this.lightning.pendingChannels({ includeRawTx: false }, DeadLineMetadata()) return res.response } async ListChannels(peerLookup = false): Promise { - this.log(DEBUG, "Listing channels") + // console.log("Listing channels") const res = await this.lightning.listChannels({ activeOnly: false, inactiveOnly: false, privateOnly: false, publicOnly: false, peer: Buffer.alloc(0), peerAliasLookup: peerLookup }, DeadLineMetadata()) return res.response } async ListClosedChannels(): Promise { - this.log(DEBUG, "Listing closed channels") + // console.log("Listing closed channels") const res = await this.lightning.closedChannels({ abandoned: true, breach: true, @@ -212,6 +206,7 @@ export default class { if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return } + // console.log("Checking health") if (!this.ready) { throw new Error("not ready") } @@ -222,69 +217,69 @@ export default class { } RestartStreams() { - this.log(INFO, "Restarting streams") + // console.log("Restarting streams") if (!this.ready || this.abortController.signal.aborted) { return } - this.log(INFO, "LND is dead, will try to reconnect in", deadLndRetrySeconds, "seconds") + this.log("LND is dead, will try to reconnect in", deadLndRetrySeconds, "seconds") const interval = setInterval(async () => { try { await this.unlockLnd() - this.log(INFO, "LND is back online") + this.log("LND is back online") clearInterval(interval) await this.Warmup() } catch (err) { - this.log(INFO, "LND still dead, will try again in", deadLndRetrySeconds, "seconds") + this.log("LND still dead, will try again in", deadLndRetrySeconds, "seconds") } }, deadLndRetrySeconds * 1000) } async SubscribeChannelEvents() { - this.log(DEBUG, "Subscribing to channel events") + // console.log("Subscribing to channel events") const stream = this.lightning.subscribeChannelEvents({}, { abort: this.abortController.signal }) stream.responses.onMessage(async channel => { const channels = await this.ListChannels() this.channelEventCb(channel, channels.channels) }) stream.responses.onError(error => { - this.log(ERROR, "Error with subscribeChannelEvents stream") + this.log("Error with subscribeChannelEvents stream") }) stream.responses.onComplete(() => { - this.log(INFO, "subscribeChannelEvents stream closed") + this.log("subscribeChannelEvents stream closed") }) } async SubscribeHtlcEvents() { - this.log(DEBUG, "Subscribing to htlc events") + // console.log("Subscribing to htlc events") const stream = this.router.subscribeHtlcEvents({}, { abort: this.abortController.signal }) stream.responses.onMessage(htlc => { this.htlcCb(htlc) }) stream.responses.onError(error => { - this.log(ERROR, "Error with subscribeHtlcEvents stream") + this.log("Error with subscribeHtlcEvents stream") }) stream.responses.onComplete(() => { - this.log(INFO, "subscribeHtlcEvents stream closed") + this.log("subscribeHtlcEvents stream closed") }) } async SubscribeNewBlock() { - this.log(DEBUG, "Subscribing to new block") + // console.log("Subscribing to new block") const { blockHeight } = await this.GetInfo() const stream = this.chainNotifier.registerBlockEpochNtfn({ height: blockHeight, hash: Buffer.alloc(0) }, { abort: this.abortController.signal }) stream.responses.onMessage(block => { this.newBlockCb(block.height) }) stream.responses.onError(error => { - this.log(ERROR, "Error with new block stream") + this.log("Error with new block stream") }) stream.responses.onComplete(() => { - this.log(INFO, "new block stream closed") + this.log("new block stream closed") }) } SubscribeAddressPaid(): void { - this.log(DEBUG, "Subscribing to address paid") + // console.log("Subscribing to address paid") const stream = this.lightning.subscribeTransactions({ account: "", endHeight: 0, @@ -303,15 +298,15 @@ export default class { } }) stream.responses.onError(error => { - this.log(ERROR, "Error with onchain tx stream") + this.log("Error with onchain tx stream") }) stream.responses.onComplete(() => { - this.log(INFO, "onchain tx stream closed") + this.log("onchain tx stream closed") }) } SubscribeInvoicePaid(): void { - this.log(DEBUG, "Subscribing to invoice paid") + // console.log("Subscribing to invoice paid") const stream = this.lightning.subscribeInvoices({ settleIndex: BigInt(this.latestKnownSettleIndex), addIndex: 0n, @@ -324,14 +319,14 @@ export default class { }) let restarted = false stream.responses.onError(error => { - this.log(ERROR, "Error with invoice stream") + this.log("Error with invoice stream") if (!restarted) { restarted = true this.RestartStreams() } }) stream.responses.onComplete(() => { - this.log(INFO, "invoice stream closed") + this.log("invoice stream closed") if (!restarted) { restarted = true this.RestartStreams() @@ -353,7 +348,6 @@ export default class { } async ListAddresses(): Promise { - this.log(DEBUG, "Listing addresses") const res = await this.walletKit.listAddresses({ accountName: "", showCustomAccounts: false }, DeadLineMetadata()) const addresses = res.response.accountWithAddresses.map(a => a.addresses.map(a => ({ address: a.address, change: a.isInternal }))).flat() addresses.forEach(a => this.addressesCache[a.address] = { isChange: a.change }) @@ -361,11 +355,11 @@ export default class { } async NewAddress(addressType: Types.AddressType, { useProvider, from }: TxActionOptions): Promise { - this.log(DEBUG, "Creating new address") // Force use of provider when bypass is enabled (addresses not supported by provider, but we should fail gracefully) if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { throw new Error("Address generation not supported when USE_ONLY_LIQUIDITY_PROVIDER is enabled") } + // console.log("Creating new address") let lndAddressType: AddressType switch (addressType) { case Types.AddressType.NESTED_PUBKEY_HASH: @@ -395,11 +389,11 @@ export default class { } async NewInvoice(value: number, memo: string, expiry: number, { useProvider, from }: TxActionOptions, blind = false): Promise { - this.log(DEBUG, "Creating new invoice") + // console.log("Creating new invoice") // Force use of provider when bypass is enabled const mustUseProvider = this.liquidProvider.getSettings().useOnlyLiquidityProvider || useProvider if (mustUseProvider) { - this.log(INFO, "using provider") + console.log("using provider") const invoice = await this.liquidProvider.AddInvoice(value, memo, from, expiry) const providerPubkey = this.liquidProvider.GetProviderPubkey() return { payRequest: invoice, providerPubkey } @@ -415,7 +409,6 @@ export default class { } async DecodeInvoice(paymentRequest: string): Promise { - this.log(DEBUG, "Decoding invoice") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { // Use light-bolt11-decoder when LND is bypassed try { @@ -441,23 +434,24 @@ export default class { throw new Error(`Failed to decode invoice: ${err.message}`) } } + // console.log("Decoding invoice") const res = await this.lightning.decodePayReq({ payReq: paymentRequest }, DeadLineMetadata()) return { numSatoshis: Number(res.response.numSatoshis), paymentHash: res.response.paymentHash } } async ChannelBalance(): Promise<{ local: number, remote: number }> { - this.log(DEBUG, "Getting channel balance") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return { local: 0, remote: 0 } } + // console.log("Getting channel balance") const res = await this.lightning.channelBalance({}) const r = res.response return { local: r.localBalance ? Number(r.localBalance.sat) : 0, remote: r.remoteBalance ? Number(r.remoteBalance.sat) : 0 } } async PayInvoice(invoice: string, amount: number, { routingFeeLimit, serviceFee }: { routingFeeLimit: number, serviceFee: number }, decodedAmount: number, { useProvider, from }: TxActionOptions, paymentIndexCb?: (index: number) => void): Promise { - this.log(DEBUG, "Paying invoice") + // console.log("Paying invoice") if (this.outgoingOpsLocked) { - this.log(ERROR, "outgoing ops locked, rejecting payment request") + this.log("outgoing ops locked, rejecting payment request") throw new Error("lnd node is currently out of sync") } // Force use of provider when bypass is enabled @@ -474,7 +468,7 @@ export default class { const stream = this.router.sendPaymentV2(req, { abort: abortController.signal }) return new Promise((res, rej) => { stream.responses.onError(error => { - this.log(ERROR, "invoice payment failed", error) + this.log("invoice payment failed", error) rej(error) }) let indexSent = false @@ -486,7 +480,7 @@ export default class { } switch (payment.status) { case Payment_PaymentStatus.FAILED: - this.log(ERROR, "invoice payment failed", payment.failureReason) + this.log("invoice payment failed", payment.failureReason) rej(PaymentFailureReason[payment.failureReason]) return case Payment_PaymentStatus.SUCCEEDED: @@ -504,7 +498,7 @@ export default class { } async EstimateChainFees(address: string, amount: number, targetConf: number): Promise { - this.log(DEBUG, "Estimating chain fees") + // console.log("Estimating chain fees") await this.Health() const res = await this.lightning.estimateFee({ addrToAmount: { [address]: BigInt(amount) }, @@ -517,13 +511,13 @@ export default class { } async PayAddress(address: string, amount: number, satPerVByte: number, label = "", { useProvider, from }: TxActionOptions): Promise { - this.log(DEBUG, "Paying address") // Address payments not supported when bypass is enabled if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { throw new Error("Address payments not supported when USE_ONLY_LIQUIDITY_PROVIDER is enabled") } + // console.log("Paying address") if (this.outgoingOpsLocked) { - this.log(ERROR, "outgoing ops locked, rejecting payment request") + this.log("outgoing ops locked, rejecting payment request") throw new Error("lnd node is currently out of sync") } if (useProvider) { @@ -541,19 +535,19 @@ export default class { } async GetTransactions(startHeight: number): Promise { - this.log(DEBUG, "Getting transactions") - const res = await this.lightning.getTransactions({ startHeight, endHeight: 0, account: "", }, DeadLineMetadata()) + // console.log("Getting transactions") + const res = await this.lightning.getTransactions({ startHeight, endHeight: 0, account: "" }, DeadLineMetadata()) return res.response } async GetChannelInfo(chanId: string) { - this.log(DEBUG, "Getting channel info") + // console.log("Getting channel info") const res = await this.lightning.getChanInfo({ chanId, chanPoint: "" }, DeadLineMetadata()) return res.response } async UpdateChannelPolicy(chanPoint: string, policy: Types.ChannelPolicy) { - this.log(DEBUG, "Updating channel policy") + // console.log("Updating channel policy") const split = chanPoint.split(':') const res = await this.lightning.updateChannelPolicy({ @@ -571,19 +565,19 @@ export default class { } async GetChannelBalance() { - this.log(DEBUG, "Getting channel balance") + // console.log("Getting channel balance") const res = await this.lightning.channelBalance({}, DeadLineMetadata()) return res.response } async GetWalletBalance() { - this.log(DEBUG, "Getting wallet balance") + // console.log("Getting wallet balance") const res = await this.lightning.walletBalance({ account: "", minConfs: 1 }, DeadLineMetadata()) return res.response } async GetTotalBalace() { - this.log(DEBUG, "Getting total balance") + // console.log("Getting total balance") const walletBalance = await this.GetWalletBalance() const confirmedWalletBalance = Number(walletBalance.confirmedBalance) this.utils.stateBundler.AddBalancePoint('walletBalance', confirmedWalletBalance) @@ -598,10 +592,10 @@ export default class { } async GetBalance(): Promise { // TODO: remove this - this.log(DEBUG, "Getting balance") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return { confirmedBalance: 0, unconfirmedBalance: 0, totalBalance: 0, channelsBalance: [] } } + // console.log("Getting balance") const wRes = await this.lightning.walletBalance({ account: "", minConfs: 1 }, DeadLineMetadata()) const { confirmedBalance, unconfirmedBalance, totalBalance } = wRes.response const { response } = await this.lightning.listChannels({ @@ -617,47 +611,33 @@ export default class { } async GetForwardingHistory(indexOffset: number, startTime = 0, endTime = 0): Promise { - this.log(DEBUG, "Getting forwarding history") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return { forwardingEvents: [], lastOffsetIndex: indexOffset } } + // console.log("Getting forwarding history") const { response } = await this.lightning.forwardingHistory({ indexOffset, numMaxEvents: 0, startTime: BigInt(startTime), endTime: BigInt(endTime), peerAliasLookup: false }, DeadLineMetadata()) return response } - async GetAllInvoices(max: number) { - this.log(DEBUG, "Getting all paid invoices") + async GetAllPaidInvoices(max: number) { if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return { invoices: [] } } + // console.log("Getting all paid invoices") const res = await this.lightning.listInvoices({ indexOffset: 0n, numMaxInvoices: BigInt(max), pendingOnly: false, reversed: true, creationDateEnd: 0n, creationDateStart: 0n }, DeadLineMetadata()) return res.response } async GetAllPayments(max: number) { - this.log(DEBUG, "Getting all payments") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return { payments: [] } } + // console.log("Getting all payments") const res = await this.lightning.listPayments({ countTotalPayments: false, includeIncomplete: false, indexOffset: 0n, maxPayments: BigInt(max), reversed: true, creationDateEnd: 0n, creationDateStart: 0n }) return res.response } - async BumpFee(txId: string, outputIndex: number, satPerVbyte: number) { - this.log(DEBUG, "Bumping fee") - const res = await this.walletKit.bumpFee({ - budget: 0n, immediate: false, targetConf: 0, satPerVbyte: BigInt(satPerVbyte), outpoint: { - txidStr: txId, - outputIndex: outputIndex, - txidBytes: Buffer.alloc(0) - }, - force: false, - satPerByte: 0 - }, DeadLineMetadata()) - return res.response - } - async GetPayment(paymentIndex: number) { - this.log(DEBUG, "Getting payment") + // console.log("Getting payment") if (paymentIndex === 0) { throw new Error("payment index starts from 1") } @@ -669,10 +649,10 @@ export default class { } async GetLatestPaymentIndex(from = 0) { - this.log(DEBUG, "Getting latest payment index") if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) { return from } + // console.log("Getting latest payment index") let indexOffset = BigInt(from) while (true) { const res = await this.lightning.listPayments({ countTotalPayments: false, includeIncomplete: false, indexOffset, maxPayments: 0n, reversed: false, creationDateEnd: 0n, creationDateStart: 0n }, DeadLineMetadata()) @@ -684,7 +664,7 @@ export default class { } async ConnectPeer(addr: { pubkey: string, host: string }) { - this.log(DEBUG, "Connecting to peer") + // console.log("Connecting to peer") const res = await this.lightning.connectPeer({ addr, perm: true, @@ -694,7 +674,7 @@ export default class { } async GetPaymentFromHash(paymentHash: string): Promise { - this.log(DEBUG, "Getting payment from hash") + // console.log("Getting payment from hash") const abortController = new AbortController() const stream = this.router.trackPaymentV2({ paymentHash: Buffer.from(paymentHash, 'hex'), @@ -716,12 +696,13 @@ export default class { } async GetTx(txid: string) { + // console.log("Getting transaction") const res = await this.walletKit.getTransaction({ txid }, DeadLineMetadata()) return res.response } async AddPeer(pub: string, host: string, port: number) { - this.log(DEBUG, "Adding peer") + // console.log("Adding peer") const res = await this.lightning.connectPeer({ addr: { pubkey: pub, @@ -734,19 +715,19 @@ export default class { } async ListPeers() { - this.log(DEBUG, "Listing peers") + // console.log("Listing peers") const res = await this.lightning.listPeers({ latestError: true }, DeadLineMetadata()) return res.response } async OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number, satsPerVByte: number): Promise { - this.log(DEBUG, "Opening channel") + // console.log("Opening channel") const abortController = new AbortController() const req = OpenChannelReq(destination, closeAddress, fundingAmount, pushSats, satsPerVByte) const stream = this.lightning.openChannel(req, { abort: abortController.signal }) return new Promise((res, rej) => { stream.responses.onMessage(message => { - this.log(DEBUG, "open channel message", message) + console.log("message", message) switch (message.update.oneofKind) { case 'chanPending': res(message) @@ -754,14 +735,14 @@ export default class { } }) stream.responses.onError(error => { - this.log(ERROR, "open channel error", error) + console.log("error", error) rej(error) }) }) } async CloseChannel(fundingTx: string, outputIndex: number, force: boolean, satPerVByte: number): Promise { - this.log(DEBUG, "Closing channel") + // console.log("Closing channel") const stream = this.lightning.closeChannel({ deliveryAddress: "", force: force, @@ -780,7 +761,7 @@ export default class { }, DeadLineMetadata()) return new Promise((res, rej) => { stream.responses.onMessage(message => { - this.log(DEBUG, "close channel message", message) + console.log("message", message) switch (message.update.oneofKind) { case 'closePending': res(message.update.closePending) @@ -788,7 +769,7 @@ export default class { } }) stream.responses.onError(error => { - this.log(ERROR, "close channel error", error) + console.log("error", error) rej(error) }) }) diff --git a/src/services/lnd/swaps.ts b/src/services/lnd/swaps.ts new file mode 100644 index 00000000..727f0e88 --- /dev/null +++ b/src/services/lnd/swaps.ts @@ -0,0 +1,657 @@ +import zkpInit from '@vulpemventures/secp256k1-zkp'; +import axios from 'axios'; +import { crypto, initEccLib, Transaction, address, Network } from 'bitcoinjs-lib'; +// import bolt11 from 'bolt11'; +import { + Musig, SwapTreeSerializer, TaprootUtils, detectSwap, + constructClaimTransaction, targetFee, OutputType, + Networks, +} from 'boltz-core'; +import { randomBytes, createHash } from 'crypto'; +import { ECPairFactory, ECPairInterface } from 'ecpair'; +import * as ecc from 'tiny-secp256k1'; +import ws from 'ws'; +import { getLogger, PubLogger, ERROR } from '../helpers/logger.js'; +import SettingsManager from '../main/settingsManager.js'; +import * as Types from '../../../proto/autogenerated/ts/types.js'; +import { BTCNetwork } from '../main/settings.js'; +import Storage from '../storage/index.js'; +import LND from './lnd.js'; +import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js'; +type InvoiceSwapResponse = { id: string, claimPublicKey: string, swapTree: string } +type InvoiceSwapInfo = { paymentHash: string, keys: ECPairInterface } +type InvoiceSwapData = { createdResponse: InvoiceSwapResponse, info: InvoiceSwapInfo } + +type TransactionSwapFees = { + percentage: number, + minerFees: { + claim: number, + lockup: number, + } +} + +type TransactionSwapFeesRes = { + BTC?: { + BTC?: { + fees: TransactionSwapFees + } + } +} + + +type TransactionSwapResponse = { + id: string, refundPublicKey: string, swapTree: string, + timeoutBlockHeight: number, lockupAddress: string, invoice: string, + onchainAmount?: number +} +type TransactionSwapInfo = { destinationAddress: string, preimage: Buffer, keys: ECPairInterface, chainFee: number } +export type TransactionSwapData = { createdResponse: TransactionSwapResponse, info: TransactionSwapInfo } +export class Swaps { + settings: SettingsManager + revSwappers: Record + // submarineSwaps: SubmarineSwaps + storage: Storage + lnd: LND + log = getLogger({ component: 'swaps' }) + constructor(settings: SettingsManager, storage: Storage) { + this.settings = settings + this.revSwappers = {} + const network = settings.getSettings().lndSettings.network + const { boltzHttpUrl, boltzWebSocketUrl, boltsHttpUrlAlt, boltsWebSocketUrlAlt } = settings.getSettings().swapsSettings + if (boltzHttpUrl && boltzWebSocketUrl) { + this.revSwappers[boltzHttpUrl] = new ReverseSwaps({ httpUrl: boltzHttpUrl, wsUrl: boltzWebSocketUrl, network }) + } + if (boltsHttpUrlAlt && boltsWebSocketUrlAlt) { + this.revSwappers[boltsHttpUrlAlt] = new ReverseSwaps({ httpUrl: boltsHttpUrlAlt, wsUrl: boltsWebSocketUrlAlt, network }) + } + this.storage = storage + } + + SetLnd = (lnd: LND) => { + this.lnd = lnd + } + + Stop = () => { } + + GetKeys = (privateKey: string) => { + const keys = ECPairFactory(ecc).fromPrivateKey(Buffer.from(privateKey, 'hex')) + return keys + } + + ListSwaps = async (appUserId: string, payments: UserInvoicePayment[], newOp: (p: UserInvoicePayment) => Types.UserOperation | undefined, getServiceFee: (amt: number) => number): Promise => { + const completedSwaps = await this.storage.paymentStorage.ListCompletedSwaps(appUserId, payments) + const pendingSwaps = await this.storage.paymentStorage.ListPendingTransactionSwaps(appUserId) + return { + swaps: completedSwaps.map(s => { + const p = s.payment + const op = p ? newOp(p) : undefined + return { + operation_payment: op, + swap_operation_id: s.swap.swap_operation_id, + address_paid: s.swap.address_paid, + failure_reason: s.swap.failure_reason, + } + }), + quotes: pendingSwaps.map(s => { + const serviceFee = getServiceFee(s.invoice_amount) + return { + swap_operation_id: s.swap_operation_id, + invoice_amount_sats: s.invoice_amount, + transaction_amount_sats: s.transaction_amount, + chain_fee_sats: s.chain_fee_sats, + service_fee_sats: serviceFee, + swap_fee_sats: s.swap_fee_sats, + service_url: s.service_url, + } + }) + } + } + GetTxSwapQuotes = async (appUserId: string, amt: number, getServiceFee: (decodedAmt: number) => number): Promise => { + if (!this.settings.getSettings().swapsSettings.enableSwaps) { + throw new Error("Swaps are not enabled") + } + const swappers = Object.values(this.revSwappers) + if (swappers.length === 0) { + throw new Error("No swap services available") + } + const res = await Promise.allSettled(swappers.map(sw => this.getTxSwapQuote(sw, appUserId, amt, getServiceFee))) + const failures: string[] = [] + const success: Types.TransactionSwapQuote[] = [] + for (const r of res) { + if (r.status === 'fulfilled') { + success.push(r.value) + } else { + failures.push(r.reason.message ? r.reason.message : r.reason.toString()) + } + } + if (success.length === 0) { + throw new Error(failures.join("\n")) + } + return success + } + + private async getTxSwapQuote(swapper: ReverseSwaps, appUserId: string, amt: number, getServiceFee: (decodedAmt: number) => number): Promise { + this.log("getting transaction swap quote") + const feesRes = await swapper.GetFees() + if (!feesRes.ok) { + throw new Error(feesRes.error) + } + const { claim, lockup } = feesRes.fees.minerFees + const minerFee = claim + lockup + const chainTotal = amt + minerFee + const res = await swapper.SwapTransaction(chainTotal) + if (!res.ok) { + throw new Error(res.error) + } + const decoded = await this.lnd.DecodeInvoice(res.createdResponse.invoice) + const swapFee = decoded.numSatoshis - chainTotal + const serviceFee = getServiceFee(decoded.numSatoshis) + const newSwap = await this.storage.paymentStorage.AddTransactionSwap({ + app_user_id: appUserId, + swap_quote_id: res.createdResponse.id, + swap_tree: JSON.stringify(res.createdResponse.swapTree), + lockup_address: res.createdResponse.lockupAddress, + refund_public_key: res.createdResponse.refundPublicKey, + timeout_block_height: res.createdResponse.timeoutBlockHeight, + invoice: res.createdResponse.invoice, + invoice_amount: decoded.numSatoshis, + transaction_amount: chainTotal, + swap_fee_sats: swapFee, + chain_fee_sats: minerFee, + preimage: res.preimage, + ephemeral_private_key: res.privKey, + ephemeral_public_key: res.pubkey, + service_url: swapper.getHttpUrl(), + }) + return { + swap_operation_id: newSwap.swap_operation_id, + swap_fee_sats: swapFee, + invoice_amount_sats: decoded.numSatoshis, + transaction_amount_sats: amt, + chain_fee_sats: minerFee, + service_fee_sats: serviceFee, + service_url: swapper.getHttpUrl(), + } + } + + async PayAddrWithSwap(appUserId: string, swapOpId: string, address: string, payInvoice: (invoice: string, amt: number) => Promise) { + if (!this.settings.getSettings().swapsSettings.enableSwaps) { + throw new Error("Swaps are not enabled") + } + this.log("paying address with swap", { appUserId, swapOpId, address }) + if (!swapOpId) { + throw new Error("request a swap quote before paying an external address") + } + const txSwap = await this.storage.paymentStorage.GetTransactionSwap(swapOpId, appUserId) + if (!txSwap) { + throw new Error("swap quote not found") + } + const info = await this.lnd.GetInfo() + if (info.blockHeight >= txSwap.timeout_block_height) { + throw new Error("swap timeout") + } + const swapper = this.revSwappers[txSwap.service_url] + if (!swapper) { + throw new Error("swapper service not found") + } + const keys = this.GetKeys(txSwap.ephemeral_private_key) + const data: TransactionSwapData = { + createdResponse: { + id: txSwap.swap_quote_id, + invoice: txSwap.invoice, + lockupAddress: txSwap.lockup_address, + refundPublicKey: txSwap.refund_public_key, + swapTree: txSwap.swap_tree, + timeoutBlockHeight: txSwap.timeout_block_height, + onchainAmount: txSwap.transaction_amount, + }, + info: { + destinationAddress: address, + keys, + chainFee: txSwap.chain_fee_sats, + preimage: Buffer.from(txSwap.preimage, 'hex'), + } + } + // the swap and the invoice payment are linked, swap will not start until the invoice payment is started, and will not complete once the invoice payment is completed + let swapResult = { ok: false, error: "swap never completed" } as { ok: true, txId: string } | { ok: false, error: string } + swapper.SubscribeToTransactionSwap(data, result => { + swapResult = result + }) + try { + await payInvoice(txSwap.invoice, txSwap.invoice_amount) + if (!swapResult.ok) { + this.log("invoice payment successful, but swap failed") + await this.storage.paymentStorage.FailTransactionSwap(swapOpId, address, swapResult.error) + throw new Error(swapResult.error) + } + this.log("swap completed successfully") + await this.storage.paymentStorage.FinalizeTransactionSwap(swapOpId, address, swapResult.txId) + } catch (err: any) { + if (swapResult.ok) { + this.log("failed to pay swap invoice, but swap completed successfully", swapResult.txId) + await this.storage.paymentStorage.FailTransactionSwap(swapOpId, address, err.message) + } else { + this.log("failed to pay swap invoice and swap failed", swapResult.error) + await this.storage.paymentStorage.FailTransactionSwap(swapOpId, address, swapResult.error) + } + throw err + } + const networkFeesTotal = txSwap.chain_fee_sats + txSwap.swap_fee_sats + return { + txId: swapResult.txId, + network_fee: networkFeesTotal + } + } +} + + + +export class ReverseSwaps { + // settings: SettingsManager + private httpUrl: string + private wsUrl: string + log: PubLogger + private network: BTCNetwork + constructor({ httpUrl, wsUrl, network }: { httpUrl: string, wsUrl: string, network: BTCNetwork }) { + this.httpUrl = httpUrl + this.wsUrl = wsUrl + this.network = network + this.log = getLogger({ component: 'ReverseSwaps' }) + initEccLib(ecc) + } + + getHttpUrl = () => { + return this.httpUrl + } + getWsUrl = () => { + return this.wsUrl + } + + calculateFees = (fees: TransactionSwapFees, receiveAmount: number) => { + const pct = fees.percentage / 100 + const minerFee = fees.minerFees.claim + fees.minerFees.lockup + + const preFee = receiveAmount + minerFee + const fee = Math.ceil(preFee * pct) + const total = preFee + fee + return { total, fee, minerFee } + } + + GetFees = async (): Promise<{ ok: true, fees: TransactionSwapFees, } | { ok: false, error: string }> => { + const url = `${this.httpUrl}/v2/swap/reverse` + const feesRes = await loggedGet(this.log, url) + if (!feesRes.ok) { + return { ok: false, error: feesRes.error } + } + if (!feesRes.data.BTC?.BTC?.fees) { + return { ok: false, error: 'No fees found for BTC to BTC swap' } + } + + return { ok: true, fees: feesRes.data.BTC.BTC.fees } + } + + SwapTransaction = async (txAmount: number): Promise<{ ok: true, createdResponse: TransactionSwapResponse, preimage: string, pubkey: string, privKey: string } | { ok: false, error: string }> => { + const preimage = randomBytes(32); + const keys = ECPairFactory(ecc).makeRandom() + if (!keys.privateKey) { + return { ok: false, error: 'Failed to generate keys' } + } + const url = `${this.httpUrl}/v2/swap/reverse` + const req: any = { + onchainAmount: txAmount, + to: 'BTC', + from: 'BTC', + claimPublicKey: Buffer.from(keys.publicKey).toString('hex'), + preimageHash: createHash('sha256').update(preimage).digest('hex'), + } + const createdResponseRes = await loggedPost(this.log, url, req) + if (!createdResponseRes.ok) { + return createdResponseRes + } + const createdResponse = createdResponseRes.data + this.log('Created transaction swap'); + this.log(createdResponse); + return { + ok: true, createdResponse, + preimage: Buffer.from(preimage).toString('hex'), + pubkey: Buffer.from(keys.publicKey).toString('hex'), + privKey: Buffer.from(keys.privateKey).toString('hex') + } + } + + SubscribeToTransactionSwap = async (data: TransactionSwapData, swapDone: (result: { ok: true, txId: string } | { ok: false, error: string }) => void) => { + const webSocket = new ws(`${this.wsUrl}/v2/ws`) + const subReq = { op: 'subscribe', channel: 'swap.update', args: [data.createdResponse.id] } + webSocket.on('open', () => { + webSocket.send(JSON.stringify(subReq)) + }) + let txId = "", isDone = false + const done = () => { + isDone = true + webSocket.close() + swapDone({ ok: true, txId }) + } + webSocket.on('error', (err) => { + this.log(ERROR, 'Error in WebSocket', err.message) + }) + webSocket.on('close', () => { + if (!isDone) { + this.log(ERROR, 'WebSocket closed before swap was done'); + swapDone({ ok: false, error: 'WebSocket closed before swap was done' }) + } + }) + webSocket.on('message', async (rawMsg) => { + try { + const result = await this.handleSwapTransactionMessage(rawMsg, data, done) + if (result) { + txId = result + } + } catch (err: any) { + this.log(ERROR, 'Error handling transaction WebSocket message', err.message) + isDone = true + webSocket.close() + swapDone({ ok: false, error: err.message }) + return + } + }) + } + + handleSwapTransactionMessage = async (rawMsg: ws.RawData, data: TransactionSwapData, done: () => void) => { + const msg = JSON.parse(rawMsg.toString('utf-8')); + if (msg.event !== 'update') { + return; + } + + this.log('Got WebSocket update'); + this.log(msg); + switch (msg.args[0].status) { + // "swap.created" means Boltz is waiting for the invoice to be paid + case 'swap.created': + this.log('Waiting invoice to be paid'); + return; + + // "transaction.mempool" means that Boltz sent an onchain transaction + case 'transaction.mempool': + const txIdRes = await this.handleTransactionMempool(data, msg.args[0].transaction.hex) + if (!txIdRes.ok) { + throw new Error(txIdRes.error) + } + return txIdRes.txId + case 'invoice.settled': + this.log('Transaction swap successful'); + done() + return; + } + } + + handleTransactionMempool = async (data: TransactionSwapData, txHex: string): Promise<{ ok: true, txId: string } | { ok: false, error: string }> => { + this.log('Creating claim transaction'); + const { createdResponse, info } = data + const { destinationAddress, keys, preimage, chainFee } = info + const boltzPublicKey = Buffer.from( + createdResponse.refundPublicKey, + 'hex', + ); + + // Create a musig signing session and tweak it with the Taptree of the swap scripts + const musig = new Musig(await zkpInit(), keys, randomBytes(32), [ + boltzPublicKey, + Buffer.from(keys.publicKey), + ]); + const tweakedKey = TaprootUtils.tweakMusig( + musig, + // swap tree can either be a string or an object + SwapTreeSerializer.deserializeSwapTree(createdResponse.swapTree).tree, + ); + + // Parse the lockup transaction and find the output relevant for the swap + const lockupTx = Transaction.fromHex(txHex); + const swapOutput = detectSwap(tweakedKey, lockupTx); + if (swapOutput === undefined) { + this.log(ERROR, 'No swap output found in lockup transaction'); + return { ok: false, error: 'No swap output found in lockup transaction' } + } + const network = getNetwork(this.network) + // Create a claim transaction to be signed cooperatively via a key path spend + const claimTx = constructClaimTransaction( + [ + { + ...swapOutput, + keys, + preimage, + cooperative: true, + type: OutputType.Taproot, + txHash: lockupTx.getHash(), + }, + ], + address.toOutputScript(destinationAddress, network), + chainFee, + ) + // Get the partial signature from Boltz + const claimUrl = `${this.httpUrl}/v2/swap/reverse/${createdResponse.id}/claim` + const claimReq = { + index: 0, + transaction: claimTx.toHex(), + preimage: preimage.toString('hex'), + pubNonce: Buffer.from(musig.getPublicNonce()).toString('hex'), + } + const boltzSigRes = await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, claimUrl, claimReq) + if (!boltzSigRes.ok) { + return boltzSigRes + } + const boltzSig = boltzSigRes.data + + // Aggregate the nonces + musig.aggregateNonces([ + [boltzPublicKey, Buffer.from(boltzSig.pubNonce, 'hex')], + ]); + + // Initialize the session to sign the claim transaction + musig.initializeSession( + claimTx.hashForWitnessV1( + 0, + [swapOutput.script], + [swapOutput.value], + Transaction.SIGHASH_DEFAULT, + ), + ); + + // Add the partial signature from Boltz + musig.addPartial( + boltzPublicKey, + Buffer.from(boltzSig.partialSignature, 'hex'), + ); + + // Create our partial signature + musig.signPartial(); + + // Witness of the input to the aggregated signature + claimTx.ins[0].witness = [musig.aggregatePartials()]; + + // Broadcast the finalized transaction + const broadcastUrl = `${this.httpUrl}/v2/chain/BTC/transaction` + const broadcastReq = { + hex: claimTx.toHex(), + } + + const broadcastResponse = await loggedPost(this.log, broadcastUrl, broadcastReq) + if (!broadcastResponse.ok) { + return broadcastResponse + } + this.log('Transaction broadcasted', broadcastResponse.data) + const txId = claimTx.getId() + return { ok: true, txId } + } +} + +const loggedPost = async (log: PubLogger, url: string, req: any): Promise<{ ok: true, data: T } | { ok: false, error: string }> => { + try { + const { data } = await axios.post(url, req) + return { ok: true, data: data as T } + } catch (err: any) { + if (err.response?.data) { + log(ERROR, 'Error sending request', err.response.data) + return { ok: false, error: JSON.stringify(err.response.data) } + } + log(ERROR, 'Error sending request', err.message) + return { ok: false, error: err.message } + } +} + +const loggedGet = async (log: PubLogger, url: string): Promise<{ ok: true, data: T } | { ok: false, error: string }> => { + try { + const { data } = await axios.get(url) + return { ok: true, data: data as T } + } catch (err: any) { + if (err.response?.data) { + log(ERROR, 'Error getting request', err.response.data) + return { ok: false, error: err.response.data } + } + log(ERROR, 'Error getting request', err.message) + return { ok: false, error: err.message } + } +} + +const getNetwork = (network: BTCNetwork): Network => { + switch (network) { + case 'mainnet': + return Networks.bitcoinMainnet + case 'testnet': + return Networks.bitcoinTestnet + case 'regtest': + return Networks.bitcoinRegtest + default: + throw new Error(`Invalid network: ${network}`) + } +} + +// Submarine swaps currently not supported, keeping the code for future reference +/* +export class SubmarineSwaps { + settings: SettingsManager + log: PubLogger + constructor(settings: SettingsManager) { + this.settings = settings + this.log = getLogger({ component: 'SubmarineSwaps' }) + } + + SwapInvoice = async (invoice: string, paymentHash: string) => { + if (!this.settings.getSettings().swapsSettings.enableSwaps) { + this.log(ERROR, 'Swaps are not enabled'); + return; + } + const keys = ECPairFactory(ecc).makeRandom() + const refundPublicKey = Buffer.from(keys.publicKey).toString('hex') + const req = { invoice, to: 'BTC', from: 'BTC', refundPublicKey } + const url = `${this.settings.getSettings().swapsSettings.boltzHttpUrl}/v2/swap/submarine` + this.log('Sending invoice swap request to', url); + const createdResponseRes = await loggedPost(this.log, url, req) + if (!createdResponseRes.ok) { + return createdResponseRes + } + const createdResponse = createdResponseRes.data + this.log('Created invoice swap'); + this.log(createdResponse); + + const webSocket = new ws(`${this.settings.getSettings().swapsSettings.boltzWebSocketUrl}/v2/ws`) + const subReq = { op: 'subscribe', channel: 'swap.update', args: [createdResponse.id] } + webSocket.on('open', () => { + webSocket.send(JSON.stringify(subReq)) + }) + + webSocket.on('message', async (rawMsg) => { + try { + await this.handleSwapInvoiceMessage(rawMsg, { createdResponse, info: { paymentHash, keys } }, () => webSocket.close()) + } catch (err: any) { + this.log(ERROR, 'Error handling invoice WebSocket message', err.message) + webSocket.close() + return + } + }); + } + + handleSwapInvoiceMessage = async (rawMsg: ws.RawData, data: InvoiceSwapData, closeWebSocket: () => void) => { + const msg = JSON.parse(rawMsg.toString('utf-8')); + if (msg.event !== 'update') { + return; + } + + this.log('Got invoice WebSocket update'); + this.log(msg); + switch (msg.args[0].status) { + // "invoice.set" means Boltz is waiting for an onchain transaction to be sent + case 'invoice.set': + this.log('Waiting for onchain transaction'); + return; + // Create a partial signature to allow Boltz to do a key path spend to claim the mainchain coins + case 'transaction.claim.pending': + await this.handleInvoiceClaimPending(data) + return; + + case 'transaction.claimed': + this.log('Invoice swap successful'); + closeWebSocket() + return; + } + + } + + handleInvoiceClaimPending = async (data: InvoiceSwapData) => { + this.log('Creating cooperative claim transaction'); + const { createdResponse, info } = data + const { paymentHash, keys } = info + const { boltzHttpUrl } = this.settings.getSettings().swapsSettings + // Get the information request to create a partial signature + const url = `${boltzHttpUrl}/v2/swap/submarine/${createdResponse.id}/claim` + const claimTxDetailsRes = await loggedGet<{ preimage: string, transactionHash: string, pubNonce: string }>(this.log, url) + if (!claimTxDetailsRes.ok) { + return claimTxDetailsRes + } + const claimTxDetails = claimTxDetailsRes.data + // Verify that Boltz actually paid the invoice by comparing the preimage hash + // of the invoice to the SHA256 hash of the preimage from the response + const claimTxPreimageHash = createHash('sha256').update(Buffer.from(claimTxDetails.preimage, 'hex')).digest() + const invoicePreimageHash = Buffer.from(paymentHash, 'hex') + + if (!claimTxPreimageHash.equals(invoicePreimageHash)) { + this.log(ERROR, 'Boltz provided invalid preimage'); + return; + } + + const boltzPublicKey = Buffer.from(createdResponse.claimPublicKey, 'hex') + + // Create a musig signing instance + const musig = new Musig(await zkpInit(), keys, randomBytes(32), [ + boltzPublicKey, + Buffer.from(keys.publicKey), + ]); + // Tweak that musig with the Taptree of the swap scripts + TaprootUtils.tweakMusig( + musig, + SwapTreeSerializer.deserializeSwapTree(createdResponse.swapTree).tree, + ); + + // Aggregate the nonces + musig.aggregateNonces([ + [boltzPublicKey, Buffer.from(claimTxDetails.pubNonce, 'hex')], + ]); + // Initialize the session to sign the transaction hash from the response + musig.initializeSession( + Buffer.from(claimTxDetails.transactionHash, 'hex'), + ); + + // Give our public nonce and the partial signature to Boltz + const claimUrl = `${boltzHttpUrl}/v2/swap/submarine/${createdResponse.id}/claim` + const claimReq = { + pubNonce: Buffer.from(musig.getPublicNonce()).toString('hex'), + partialSignature: Buffer.from(musig.signPartial()).toString('hex'), + } + const claimResponseRes = await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, claimUrl, claimReq) + if (!claimResponseRes.ok) { + return claimResponseRes + } + const claimResponse = claimResponseRes.data + this.log('Claim response', claimResponse) + } +} +*/ \ No newline at end of file diff --git a/src/services/lnd/swaps/reverseSwaps.ts b/src/services/lnd/swaps/reverseSwaps.ts deleted file mode 100644 index 83dddc37..00000000 --- a/src/services/lnd/swaps/reverseSwaps.ts +++ /dev/null @@ -1,299 +0,0 @@ -import secp256k1ZkpModule from '@vulpemventures/secp256k1-zkp'; -const zkpInit = (secp256k1ZkpModule as any).default || secp256k1ZkpModule; -import { initEccLib, Transaction, address } from 'bitcoinjs-lib'; -// import bolt11 from 'bolt11'; -import { - Musig, SwapTreeSerializer, TaprootUtils, detectSwap, - constructClaimTransaction, OutputType, constructRefundTransaction -} from 'boltz-core'; -import { randomBytes, createHash } from 'crypto'; -import { ECPairFactory, ECPairInterface } from 'ecpair'; -import * as ecc from 'tiny-secp256k1'; -import ws from 'ws'; -import { getLogger, PubLogger, ERROR } from '../../helpers/logger.js'; -import { BTCNetwork } from '../../main/settings.js'; -import { loggedGet, loggedPost, getNetwork } from './swapHelpers.js'; - - -type TransactionSwapFees = { - percentage: number, - minerFees: { - claim: number, - lockup: number, - } -} - -type TransactionSwapFeesRes = { - BTC?: { - BTC?: { - fees: TransactionSwapFees - } - } -} - - -type TransactionSwapResponse = { - id: string, refundPublicKey: string, swapTree: string, - timeoutBlockHeight: number, lockupAddress: string, invoice: string, - onchainAmount?: number -} -type TransactionSwapInfo = { destinationAddress: string, preimage: Buffer, keys: ECPairInterface, chainFee: number } -export type TransactionSwapData = { createdResponse: TransactionSwapResponse, info: TransactionSwapInfo } - - - -export class ReverseSwaps { - // settings: SettingsManager - private httpUrl: string - private wsUrl: string - log: PubLogger - private network: BTCNetwork - constructor({ httpUrl, wsUrl, network }: { httpUrl: string, wsUrl: string, network: BTCNetwork }) { - this.httpUrl = httpUrl - this.wsUrl = wsUrl - this.network = network - this.log = getLogger({ component: 'ReverseSwaps' }) - initEccLib(ecc) - } - - getHttpUrl = () => { - return this.httpUrl - } - getWsUrl = () => { - return this.wsUrl - } - - calculateFees = (fees: TransactionSwapFees, receiveAmount: number) => { - const pct = fees.percentage / 100 - const minerFee = fees.minerFees.claim + fees.minerFees.lockup - - const preFee = receiveAmount + minerFee - const fee = Math.ceil(preFee * pct) - const total = preFee + fee - return { total, fee, minerFee } - } - - GetFees = async (): Promise<{ ok: true, fees: TransactionSwapFees, } | { ok: false, error: string }> => { - const url = `${this.httpUrl}/v2/swap/reverse` - const feesRes = await loggedGet(this.log, url) - if (!feesRes.ok) { - return { ok: false, error: feesRes.error } - } - if (!feesRes.data.BTC?.BTC?.fees) { - return { ok: false, error: 'No fees found for BTC to BTC swap' } - } - - return { ok: true, fees: feesRes.data.BTC.BTC.fees } - } - - SwapTransaction = async (txAmount: number): Promise<{ ok: true, createdResponse: TransactionSwapResponse, preimage: string, pubkey: string, privKey: string } | { ok: false, error: string }> => { - const preimage = randomBytes(32); - const keys = ECPairFactory(ecc).makeRandom() - if (!keys.privateKey) { - return { ok: false, error: 'Failed to generate keys' } - } - const url = `${this.httpUrl}/v2/swap/reverse` - const req: any = { - onchainAmount: txAmount, - to: 'BTC', - from: 'BTC', - claimPublicKey: Buffer.from(keys.publicKey).toString('hex'), - preimageHash: createHash('sha256').update(preimage).digest('hex'), - } - const createdResponseRes = await loggedPost(this.log, url, req) - if (!createdResponseRes.ok) { - return createdResponseRes - } - const createdResponse = createdResponseRes.data - this.log('Created transaction swap'); - this.log(createdResponse); - return { - ok: true, createdResponse, - preimage: Buffer.from(preimage).toString('hex'), - pubkey: Buffer.from(keys.publicKey).toString('hex'), - privKey: Buffer.from(keys.privateKey).toString('hex') - } - } - - SubscribeToTransactionSwap = async (data: TransactionSwapData, swapDone: (result: { ok: true, txId: string } | { ok: false, error: string }) => void) => { - const webSocket = new ws(`${this.wsUrl}/v2/ws`) - const subReq = { op: 'subscribe', channel: 'swap.update', args: [data.createdResponse.id] } - webSocket.on('open', () => { - webSocket.send(JSON.stringify(subReq)) - }) - const interval = setInterval(() => { - webSocket.ping() - }, 30 * 1000) - let txId = "", isDone = false - const done = (failureReason?: string) => { - isDone = true - clearInterval(interval) - webSocket.close() - if (failureReason) { - swapDone({ ok: false, error: failureReason }) - } else { - swapDone({ ok: true, txId }) - } - } - webSocket.on('pong', () => { - this.log('WebSocket transaction swap pong received') - }) - webSocket.on('error', (err) => { - this.log(ERROR, 'Error in WebSocket', err.message) - }) - webSocket.on('close', () => { - if (!isDone) { - this.log(ERROR, 'WebSocket closed before swap was done'); - done('WebSocket closed before swap was done') - } - }) - webSocket.on('message', async (rawMsg) => { - try { - const result = await this.handleSwapTransactionMessage(rawMsg, data, done) - if (result) { - txId = result - } - } catch (err: any) { - this.log(ERROR, 'Error handling transaction WebSocket message', err.message) - done(err.message) - return - } - }) - } - - handleSwapTransactionMessage = async (rawMsg: ws.RawData, data: TransactionSwapData, done: (failureReason?: string) => void) => { - const msg = JSON.parse(rawMsg.toString('utf-8')); - if (msg.event !== 'update') { - return; - } - - this.log('Got WebSocket update'); - this.log(msg); - switch (msg.args[0].status) { - // "swap.created" means Boltz is waiting for the invoice to be paid - case 'swap.created': - this.log('Waiting invoice to be paid'); - return; - - // "transaction.mempool" means that Boltz sent an onchain transaction - case 'transaction.mempool': - const txIdRes = await this.handleTransactionMempool(data, msg.args[0].transaction.hex) - if (!txIdRes.ok) { - throw new Error(txIdRes.error) - } - return txIdRes.txId - case 'invoice.settled': - this.log('Transaction swap successful'); - done() - return; - case 'invoice.expired': - case 'swap.expired': - case 'transaction.failed': - done(`swap ${data.createdResponse.id} failed with status ${msg.args[0].status}`) - return; - default: - this.log('Unknown swap transaction WebSocket message', msg) - return; - - } - } - - handleTransactionMempool = async (data: TransactionSwapData, txHex: string): Promise<{ ok: true, txId: string } | { ok: false, error: string }> => { - this.log('Creating claim transaction'); - const { createdResponse, info } = data - const { destinationAddress, keys, preimage, chainFee } = info - const boltzPublicKey = Buffer.from( - createdResponse.refundPublicKey, - 'hex', - ); - - // Create a musig signing session and tweak it with the Taptree of the swap scripts - const musig = new Musig(await zkpInit(), keys, randomBytes(32), [ - boltzPublicKey, - Buffer.from(keys.publicKey), - ]); - const tweakedKey = TaprootUtils.tweakMusig( - musig, - // swap tree can either be a string or an object - SwapTreeSerializer.deserializeSwapTree(createdResponse.swapTree).tree, - ); - - // Parse the lockup transaction and find the output relevant for the swap - const lockupTx = Transaction.fromHex(txHex); - const swapOutput = detectSwap(tweakedKey, lockupTx); - if (swapOutput === undefined) { - this.log(ERROR, 'No swap output found in lockup transaction'); - return { ok: false, error: 'No swap output found in lockup transaction' } - } - const network = getNetwork(this.network) - // Create a claim transaction to be signed cooperatively via a key path spend - const claimTx = constructClaimTransaction( - [ - { - ...swapOutput, - keys, - preimage, - cooperative: true, - type: OutputType.Taproot, - txHash: lockupTx.getHash(), - }, - ], - address.toOutputScript(destinationAddress, network), - chainFee, - ) - // Get the partial signature from Boltz - const claimUrl = `${this.httpUrl}/v2/swap/reverse/${createdResponse.id}/claim` - const claimReq = { - index: 0, - transaction: claimTx.toHex(), - preimage: preimage.toString('hex'), - pubNonce: Buffer.from(musig.getPublicNonce()).toString('hex'), - } - const boltzSigRes = await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, claimUrl, claimReq) - if (!boltzSigRes.ok) { - return boltzSigRes - } - const boltzSig = boltzSigRes.data - - // Aggregate the nonces - musig.aggregateNonces([ - [boltzPublicKey, Buffer.from(boltzSig.pubNonce, 'hex')], - ]); - - // Initialize the session to sign the claim transaction - musig.initializeSession( - claimTx.hashForWitnessV1( - 0, - [swapOutput.script], - [swapOutput.value], - Transaction.SIGHASH_DEFAULT, - ), - ); - - // Add the partial signature from Boltz - musig.addPartial( - boltzPublicKey, - Buffer.from(boltzSig.partialSignature, 'hex'), - ); - - // Create our partial signature - musig.signPartial(); - - // Witness of the input to the aggregated signature - claimTx.ins[0].witness = [musig.aggregatePartials()]; - - // Broadcast the finalized transaction - const broadcastUrl = `${this.httpUrl}/v2/chain/BTC/transaction` - const broadcastReq = { - hex: claimTx.toHex(), - } - - const broadcastResponse = await loggedPost(this.log, broadcastUrl, broadcastReq) - if (!broadcastResponse.ok) { - return broadcastResponse - } - this.log('Transaction broadcasted', broadcastResponse.data) - const txId = claimTx.getId() - return { ok: true, txId } - } -} \ No newline at end of file diff --git a/src/services/lnd/swaps/submarineSwaps.ts b/src/services/lnd/swaps/submarineSwaps.ts deleted file mode 100644 index 6e4beba8..00000000 --- a/src/services/lnd/swaps/submarineSwaps.ts +++ /dev/null @@ -1,539 +0,0 @@ -import secp256k1ZkpModule from '@vulpemventures/secp256k1-zkp'; -const zkpInit = (secp256k1ZkpModule as any).default || secp256k1ZkpModule; -// import bolt11 from 'bolt11'; -import { - Musig, SwapTreeSerializer, TaprootUtils, constructRefundTransaction, - detectSwap, OutputType, targetFee -} from 'boltz-core'; -import { randomBytes, createHash } from 'crypto'; -import { ECPairFactory, ECPairInterface } from 'ecpair'; -import * as ecc from 'tiny-secp256k1'; -import { Transaction, address } from 'bitcoinjs-lib'; -import ws from 'ws'; -import { getLogger, PubLogger, ERROR } from '../../helpers/logger.js'; -import { loggedGet, loggedPost, getNetwork } from './swapHelpers.js'; -import { BTCNetwork } from '../../main/settings.js'; - -/* type InvoiceSwapFees = { - hash: string, - rate: number, - limits: { - maximal: number, - minimal: number, - maximalZeroConf: number - }, - fees: { - percentage: number, - minerFees: number, - } -} */ - -type InvoiceSwapFees = { - percentage: number, - minerFees: number, -} - -type InvoiceSwapFeesRes = { - BTC?: { - BTC?: { - fees: InvoiceSwapFees - } - } -} -type InvoiceSwapResponse = { - id: string, claimPublicKey: string, swapTree: string, timeoutBlockHeight: number, - expectedAmount: number, address: string -} -type InvoiceSwapInfo = { paymentHash: string, keys: ECPairInterface } -export type InvoiceSwapData = { createdResponse: InvoiceSwapResponse, info: InvoiceSwapInfo } - -export class SubmarineSwaps { - private httpUrl: string - private wsUrl: string - private network: BTCNetwork - log: PubLogger - constructor({ httpUrl, wsUrl, network }: { httpUrl: string, wsUrl: string, network: BTCNetwork }) { - this.httpUrl = httpUrl - this.wsUrl = wsUrl - this.network = network - this.log = getLogger({ component: 'SubmarineSwaps' }) - } - - getHttpUrl = () => { - return this.httpUrl - } - getWsUrl = () => { - return this.wsUrl - } - - GetFees = async (): Promise<{ ok: true, fees: InvoiceSwapFees, } | { ok: false, error: string }> => { - const url = `${this.httpUrl}/v2/swap/submarine` - const feesRes = await loggedGet(this.log, url) - if (!feesRes.ok) { - return { ok: false, error: feesRes.error } - } - if (!feesRes.data.BTC?.BTC?.fees) { - return { ok: false, error: 'No fees found for BTC to BTC swap' } - } - return { ok: true, fees: feesRes.data.BTC.BTC.fees } - } - - SwapInvoice = async (invoice: string): Promise<{ ok: true, createdResponse: InvoiceSwapResponse, pubkey: string, privKey: string } | { ok: false, error: string }> => { - const keys = ECPairFactory(ecc).makeRandom() - if (!keys.privateKey) { - return { ok: false, error: 'Failed to generate keys' } - } - const refundPublicKey = Buffer.from(keys.publicKey).toString('hex') - const req = { invoice, to: 'BTC', from: 'BTC', refundPublicKey } - const url = `${this.httpUrl}/v2/swap/submarine` - this.log('Sending invoice swap request to', url); - const createdResponseRes = await loggedPost(this.log, url, req) - if (!createdResponseRes.ok) { - return createdResponseRes - } - const createdResponse = createdResponseRes.data - this.log('Created invoice swap'); - this.log(createdResponse); - return { - ok: true, createdResponse, - pubkey: refundPublicKey, - privKey: Buffer.from(keys.privateKey).toString('hex') - } - - } - - /** - * Get the lockup transaction for a swap from Boltz - */ - private getLockupTransaction = async (swapId: string): Promise<{ ok: true, data: { hex: string } } | { ok: false, error: string }> => { - const url = `${this.httpUrl}/v2/swap/submarine/${swapId}/transaction` - return await loggedGet<{ hex: string }>(this.log, url) - } - - /** - * Get partial refund signature from Boltz for cooperative refund - */ - private getPartialRefundSignature = async ( - swapId: string, - pubNonce: Buffer, - transaction: Transaction, - index: number - ): Promise<{ ok: true, data: { pubNonce: string, partialSignature: string } } | { ok: false, error: string }> => { - const url = `${this.httpUrl}/v2/swap/submarine/${swapId}/refund` - const req = { - index, - pubNonce: pubNonce.toString('hex'), - transaction: transaction.toHex() - } - return await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, url, req) - } - - /** - * Constructs a Taproot refund transaction (cooperative or uncooperative) - */ - private constructTaprootRefund = async ( - swapId: string, - claimPublicKey: string, - swapTree: string, - timeoutBlockHeight: number, - lockupTx: Transaction, - privateKey: ECPairInterface, - refundAddress: string, - feePerVbyte: number, - cooperative: boolean = true, - allowUncooperativeFallback: boolean = true, - cooperativeErrorMessage?: string - ): Promise<{ - ok: true, - transaction: Transaction, - cooperativeError?: string - } | { - ok: false, - error: string - }> => { - this.log(`Constructing ${cooperative ? 'cooperative' : 'uncooperative'} Taproot refund for swap ${swapId}`) - - const boltzPublicKey = Buffer.from(claimPublicKey, 'hex') - const swapTreeDeserialized = SwapTreeSerializer.deserializeSwapTree(swapTree) - - // Create musig and tweak it - let musig = new Musig(await zkpInit(), privateKey, randomBytes(32), [ - boltzPublicKey, - Buffer.from(privateKey.publicKey), - ]) - const tweakedKey = TaprootUtils.tweakMusig(musig, swapTreeDeserialized.tree) - - // Detect the swap output in the lockup transaction - const swapOutput = detectSwap(tweakedKey, lockupTx) - if (!swapOutput) { - return { ok: false, error: 'Could not detect swap output in lockup transaction' } - } - - const network = getNetwork(this.network) - // const decodedAddress = address.fromBech32(refundAddress) - - const details = [ - { - ...swapOutput, - keys: privateKey, - cooperative, - type: OutputType.Taproot, - txHash: lockupTx.getHash(), - swapTree: swapTreeDeserialized, - internalKey: musig.getAggregatedPublicKey(), - } - ] - const outputScript = address.toOutputScript(refundAddress, network) - // Construct the refund transaction: targetFee converts sat/vbyte rate to flat fee - const refundTx = targetFee( - feePerVbyte, - (fee) => constructRefundTransaction( - details, - outputScript, - cooperative ? 0 : timeoutBlockHeight, - fee, - true - ) - ) - - if (!cooperative) { - return { - ok: true, - transaction: refundTx, - cooperativeError: cooperativeErrorMessage, - } - } - - // For cooperative refund, get Boltz's partial signature - try { - musig = new Musig(await zkpInit(), privateKey, randomBytes(32), [ - boltzPublicKey, - Buffer.from(privateKey.publicKey), - ]) - // Get the partial signature from Boltz - const boltzSigRes = await this.getPartialRefundSignature( - swapId, - Buffer.from(musig.getPublicNonce()), - refundTx, - 0 - ) - - if (!boltzSigRes.ok) { - this.log(ERROR, 'Failed to get Boltz partial signature') - if (!allowUncooperativeFallback) { - return { ok: false, error: `Failed to get Boltz partial signature: ${boltzSigRes.error}` } - } - this.log(ERROR, 'Falling back to uncooperative refund') - // Fallback to uncooperative refund - return await this.constructTaprootRefund( - swapId, - claimPublicKey, - swapTree, - timeoutBlockHeight, - lockupTx, - privateKey, - refundAddress, - feePerVbyte, - false, - allowUncooperativeFallback, - boltzSigRes.error - ) - } - - const boltzSig = boltzSigRes.data - - // Aggregate nonces - musig.aggregateNonces([ - [boltzPublicKey, Musig.parsePubNonce(boltzSig.pubNonce)], - ]) - - // Tweak musig again after aggregating nonces - TaprootUtils.tweakMusig(musig, swapTreeDeserialized.tree) - - // Initialize session and sign - musig.initializeSession( - TaprootUtils.hashForWitnessV1( - details, - refundTx, - 0 - ) - ) - - musig.signPartial() - musig.addPartial(boltzPublicKey, Buffer.from(boltzSig.partialSignature, 'hex')) - - // Set the witness to the aggregated signature - refundTx.ins[0].witness = [musig.aggregatePartials()] - - return { ok: true, transaction: refundTx } - } catch (error: any) { - this.log(ERROR, 'Cooperative refund failed:', error.message) - if (!allowUncooperativeFallback) { - return { ok: false, error: `Cooperative refund failed: ${error.message}` } - } - // Fallback to uncooperative refund - return await this.constructTaprootRefund( - swapId, - claimPublicKey, - swapTree, - timeoutBlockHeight, - lockupTx, - privateKey, - refundAddress, - feePerVbyte, - false, - allowUncooperativeFallback, - error.message - ) - } - } - - /** - * Broadcasts a refund transaction - */ - private broadcastRefundTransaction = async (transaction: Transaction): Promise<{ ok: true, txId: string } | { ok: false, error: string }> => { - const url = `${this.httpUrl}/v2/chain/BTC/transaction` - const req = { hex: transaction.toHex() } - - const result = await loggedPost<{ id: string }>(this.log, url, req) - if (!result.ok) { - return result - } - - return { ok: true, txId: result.data.id } - } - - /** - * Refund a submarine swap - * @param swapId - The swap ID - * @param claimPublicKey - Boltz's claim public key - * @param swapTree - The swap tree - * @param timeoutBlockHeight - The timeout block height - * @param privateKey - The refund private key (hex string) - * @param refundAddress - The address to refund to - * @param currentHeight - The current block height - * @param lockupTxHex - The lockup transaction hex (optional, will fetch from Boltz if not provided) - * @param feePerVbyte - Fee rate in sat/vbyte (optional, will use default if not provided) - */ - RefundSwap = async (params: { - swapId: string, - claimPublicKey: string, - swapTree: string, - timeoutBlockHeight: number, - privateKeyHex: string, - refundAddress: string, - currentHeight: number, - lockupTxHex?: string, - feePerVbyte?: number, - allowEarlyRefund?: boolean - }): Promise<{ ok: true, publish: { done: false, txHex: string, txId: string } | { done: true, txId: string } } | { ok: false, error: string }> => { - const { swapId, claimPublicKey, swapTree, timeoutBlockHeight, privateKeyHex, refundAddress, currentHeight, lockupTxHex, feePerVbyte = 2, allowEarlyRefund = false } = params - - this.log('Starting refund process for swap:', swapId) - - // Get the lockup transaction (from parameter or fetch from Boltz) - let lockupTx: Transaction - if (lockupTxHex) { - this.log('Using provided lockup transaction hex') - lockupTx = Transaction.fromHex(lockupTxHex) - } else { - this.log('Fetching lockup transaction from Boltz') - const lockupTxRes = await this.getLockupTransaction(swapId) - if (!lockupTxRes.ok) { - return { ok: false, error: `Failed to get lockup transaction: ${lockupTxRes.error}` } - } - lockupTx = Transaction.fromHex(lockupTxRes.data.hex) - } - this.log('Lockup transaction retrieved:', lockupTx.getId()) - - const hasTimedOut = currentHeight >= timeoutBlockHeight - - // For stuck swaps, only allow refund after timeout. For completed (failed) swaps, - // we may attempt a cooperative refund before timeout. - if (!hasTimedOut && !allowEarlyRefund) { - return { - ok: false, - error: `Swap has not timed out yet. Current height: ${currentHeight}, timeout: ${timeoutBlockHeight}` - } - } - if (hasTimedOut) { - this.log(`Swap has timed out. Current height: ${currentHeight}, timeout: ${timeoutBlockHeight}`) - } else { - this.log(`Swap has not timed out yet, attempting cooperative refund`) - } - - // Parse the private key - const privateKey = ECPairFactory(ecc).fromPrivateKey(Buffer.from(privateKeyHex, 'hex')) - - // Construct the refund transaction (tries cooperative first, then falls back to uncooperative) - const refundTxRes = await this.constructTaprootRefund( - swapId, - claimPublicKey, - swapTree, - timeoutBlockHeight, - lockupTx, - privateKey, - refundAddress, - feePerVbyte, - true, // Try cooperative first - hasTimedOut // only allow uncooperative fallback once timeout has passed - ) - - if (!refundTxRes.ok) { - return { ok: false, error: refundTxRes.error } - } - - const cooperative = !refundTxRes.cooperativeError - this.log(`Refund transaction constructed (${cooperative ? 'cooperative' : 'uncooperative'}):`, refundTxRes.transaction.getId()) - if (!cooperative) { - return { ok: true, publish: { done: false, txHex: refundTxRes.transaction.toHex(), txId: refundTxRes.transaction.getId() } } - } - // Broadcast the refund transaction - const broadcastRes = await this.broadcastRefundTransaction(refundTxRes.transaction) - if (!broadcastRes.ok) { - return { ok: false, error: `Failed to broadcast refund transaction: ${broadcastRes.error}` } - } - - this.log('Refund transaction broadcasted successfully:', broadcastRes.txId) - return { ok: true, publish: { done: true, txId: broadcastRes.txId } } - } - - SubscribeToInvoiceSwap = (data: InvoiceSwapData, swapDone: (result: { ok: true } | { ok: false, error: string }) => void, waitingTx: () => void) => { - this.log("subscribing to invoice swap", { id: data.createdResponse.id }) - const webSocket = new ws(`${this.wsUrl}/v2/ws`) - const subReq = { op: 'subscribe', channel: 'swap.update', args: [data.createdResponse.id] } - webSocket.on('open', () => { - webSocket.send(JSON.stringify(subReq)) - }) - const interval = setInterval(() => { - webSocket.ping() - }, 30 * 1000) - let isDone = false - const done = (failureReason?: string) => { - isDone = true - clearInterval(interval) - webSocket.close() - if (failureReason) { - swapDone({ ok: false, error: failureReason }) - } else { - swapDone({ ok: true }) - } - } - webSocket.on('pong', () => { - this.log('WebSocket invoice swap pong received') - }) - webSocket.on('error', (err) => { - this.log(ERROR, 'Error in WebSocket', err.message) - }) - webSocket.on('close', () => { - if (!isDone) { - this.log(ERROR, 'WebSocket closed before swap was done'); - done('WebSocket closed before swap was done') - } - }) - webSocket.on('message', async (rawMsg) => { - try { - await this.handleSwapInvoiceMessage(rawMsg, data, done, waitingTx) - } catch (err: any) { - this.log(ERROR, 'Error handling invoice WebSocket message', err.message) - done(err.message) - return - } - }); - return () => { - webSocket.close() - } - } - - handleSwapInvoiceMessage = async (rawMsg: ws.RawData, data: InvoiceSwapData, closeWebSocket: (failureReason?: string) => void, waitingTx: () => void) => { - const msg = JSON.parse(rawMsg.toString('utf-8')); - if (msg.event !== 'update') { - return; - } - - this.log('Got invoice WebSocket update'); - this.log(msg); - switch (msg.args[0].status) { - // "invoice.set" means Boltz is waiting for an onchain transaction to be sent - case 'invoice.set': - this.log('Waiting for onchain transaction'); - waitingTx() - return; - // Create a partial signature to allow Boltz to do a key path spend to claim the mainchain coins - case 'transaction.claim.pending': - await this.handleInvoiceClaimPending(data) - return; - - case 'transaction.claimed': - this.log('Invoice swap successful'); - closeWebSocket() - return; - case 'swap.expired': - case 'transaction.lockupFailed': - case 'invoice.failedToPay': - closeWebSocket(`swap ${data.createdResponse.id} failed with status ${msg.args[0].status}`) - return; - default: - this.log('Unknown swap invoice WebSocket message', msg) - return; - } - - } - - handleInvoiceClaimPending = async (data: InvoiceSwapData) => { - this.log('Creating cooperative claim transaction'); - const { createdResponse, info } = data - const { paymentHash, keys } = info - // Get the information request to create a partial signature - const url = `${this.httpUrl}/v2/swap/submarine/${createdResponse.id}/claim` - const claimTxDetailsRes = await loggedGet<{ preimage: string, transactionHash: string, pubNonce: string }>(this.log, url) - if (!claimTxDetailsRes.ok) { - return claimTxDetailsRes - } - const claimTxDetails = claimTxDetailsRes.data - // Verify that Boltz actually paid the invoice by comparing the preimage hash - // of the invoice to the SHA256 hash of the preimage from the response - const claimTxPreimageHash = createHash('sha256').update(Buffer.from(claimTxDetails.preimage, 'hex')).digest() - const invoicePreimageHash = Buffer.from(paymentHash, 'hex') - - if (!claimTxPreimageHash.equals(invoicePreimageHash)) { - this.log(ERROR, 'Boltz provided invalid preimage'); - return; - } - - const boltzPublicKey = Buffer.from(createdResponse.claimPublicKey, 'hex') - - // Create a musig signing instance - const musig = new Musig(await zkpInit(), keys, randomBytes(32), [ - boltzPublicKey, - Buffer.from(keys.publicKey), - ]); - // Tweak that musig with the Taptree of the swap scripts - TaprootUtils.tweakMusig( - musig, - SwapTreeSerializer.deserializeSwapTree(createdResponse.swapTree).tree, - ); - - // Aggregate the nonces - musig.aggregateNonces([ - [boltzPublicKey, Buffer.from(claimTxDetails.pubNonce, 'hex')], - ]); - // Initialize the session to sign the transaction hash from the response - musig.initializeSession( - Buffer.from(claimTxDetails.transactionHash, 'hex'), - ); - - // Give our public nonce and the partial signature to Boltz - const claimUrl = `${this.httpUrl}/v2/swap/submarine/${createdResponse.id}/claim` - const claimReq = { - pubNonce: Buffer.from(musig.getPublicNonce()).toString('hex'), - partialSignature: Buffer.from(musig.signPartial()).toString('hex'), - } - const claimResponseRes = await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, claimUrl, claimReq) - if (!claimResponseRes.ok) { - return claimResponseRes - } - const claimResponse = claimResponseRes.data - this.log('Claim response', claimResponse) - } -} diff --git a/src/services/lnd/swaps/swapHelpers.ts b/src/services/lnd/swaps/swapHelpers.ts deleted file mode 100644 index 8c34f4fd..00000000 --- a/src/services/lnd/swaps/swapHelpers.ts +++ /dev/null @@ -1,50 +0,0 @@ -import axios from 'axios'; -import { Network } from 'bitcoinjs-lib'; -// import bolt11 from 'bolt11'; -import { - Networks, -} from 'boltz-core'; -import { PubLogger, ERROR } from '../../helpers/logger.js'; -import { BTCNetwork } from '../../main/settings.js'; - - -export const loggedPost = async (log: PubLogger, url: string, req: any): Promise<{ ok: true, data: T } | { ok: false, error: string }> => { - try { - const { data } = await axios.post(url, req) - return { ok: true, data: data as T } - } catch (err: any) { - if (err.response?.data) { - log(ERROR, 'Error sending request', err.response.data) - return { ok: false, error: JSON.stringify(err.response.data) } - } - log(ERROR, 'Error sending request', err.message) - return { ok: false, error: err.message } - } -} - -export const loggedGet = async (log: PubLogger, url: string): Promise<{ ok: true, data: T } | { ok: false, error: string }> => { - try { - const { data } = await axios.get(url) - return { ok: true, data: data as T } - } catch (err: any) { - if (err.response?.data) { - log(ERROR, 'Error getting request', err.response.data) - return { ok: false, error: err.response.data } - } - log(ERROR, 'Error getting request', err.message) - return { ok: false, error: err.message } - } -} - -export const getNetwork = (network: BTCNetwork): Network => { - switch (network) { - case 'mainnet': - return Networks.bitcoinMainnet - case 'testnet': - return Networks.bitcoinTestnet - case 'regtest': - return Networks.bitcoinRegtest - default: - throw new Error(`Invalid network: ${network}`) - } -} \ No newline at end of file diff --git a/src/services/lnd/swaps/swaps.ts b/src/services/lnd/swaps/swaps.ts deleted file mode 100644 index 0aaf9e32..00000000 --- a/src/services/lnd/swaps/swaps.ts +++ /dev/null @@ -1,448 +0,0 @@ -import { ECPairFactory } from 'ecpair'; -import * as ecc from 'tiny-secp256k1'; -import { getLogger } from '../../helpers/logger.js'; -import SettingsManager from '../../main/settingsManager.js'; -import * as Types from '../../../../proto/autogenerated/ts/types.js'; -import Storage from '../../storage/index.js'; -import LND from '../lnd.js'; -import { UserInvoicePayment } from '../../storage/entity/UserInvoicePayment.js'; -import { ReverseSwaps, TransactionSwapData } from './reverseSwaps.js'; -import { SubmarineSwaps, InvoiceSwapData } from './submarineSwaps.js'; -import { InvoiceSwap } from '../../storage/entity/InvoiceSwap.js'; -import { TransactionSwap } from '../../storage/entity/TransactionSwap.js'; - - -export class Swaps { - settings: SettingsManager - revSwappers: Record - subSwappers: Record - storage: Storage - lnd: LND - waitingSwaps: Record = {} - log = getLogger({ component: 'swaps' }) - constructor(settings: SettingsManager, storage: Storage) { - this.settings = settings - this.revSwappers = {} - this.subSwappers = {} - const network = settings.getSettings().lndSettings.network - const { boltzHttpUrl, boltzWebSocketUrl, boltsHttpUrlAlt, boltsWebSocketUrlAlt } = settings.getSettings().swapsSettings - if (boltzHttpUrl && boltzWebSocketUrl) { - this.revSwappers[boltzHttpUrl] = new ReverseSwaps({ httpUrl: boltzHttpUrl, wsUrl: boltzWebSocketUrl, network }) - this.subSwappers[boltzHttpUrl] = new SubmarineSwaps({ httpUrl: boltzHttpUrl, wsUrl: boltzWebSocketUrl, network }) - } - if (boltsHttpUrlAlt && boltsWebSocketUrlAlt) { - this.revSwappers[boltsHttpUrlAlt] = new ReverseSwaps({ httpUrl: boltsHttpUrlAlt, wsUrl: boltsWebSocketUrlAlt, network }) - this.subSwappers[boltsHttpUrlAlt] = new SubmarineSwaps({ httpUrl: boltsHttpUrlAlt, wsUrl: boltsWebSocketUrlAlt, network }) - } - this.storage = storage - } - - SetLnd = (lnd: LND) => { - this.lnd = lnd - } - - Stop = () => { } - - GetKeys = (privateKey: string) => { - const keys = ECPairFactory(ecc).fromPrivateKey(Buffer.from(privateKey, 'hex')) - return keys - } - - GetInvoiceSwapQuotes = async (appUserId: string, invoice: string): Promise => { - if (!this.settings.getSettings().swapsSettings.enableSwaps) { - throw new Error("Swaps are not enabled") - } - const swappers = Object.values(this.subSwappers) - if (swappers.length === 0) { - throw new Error("No swap services available") - } - const res = await Promise.allSettled(swappers.map(sw => this.getInvoiceSwapQuote(sw, appUserId, invoice))) - const failures: string[] = [] - const success: Types.InvoiceSwapQuote[] = [] - for (const r of res) { - if (r.status === 'fulfilled') { - success.push(r.value) - } else { - failures.push(r.reason.message ? r.reason.message : r.reason.toString()) - } - } - if (success.length === 0) { - throw new Error(failures.join("\n")) - } - return success - } - - private mapInvoiceSwapQuote = (s: InvoiceSwap): Types.InvoiceSwapQuote => { - return { - swap_operation_id: s.swap_operation_id, - invoice: s.invoice, - invoice_amount_sats: s.invoice_amount, - address: s.address, - transaction_amount_sats: s.transaction_amount, - chain_fee_sats: s.chain_fee_sats, - service_fee_sats: 0, - service_url: s.service_url, - swap_fee_sats: s.swap_fee_sats, - tx_id: s.tx_id, - paid_at_unix: s.paid_at_unix || (s.tx_id ? 1 : 0), - expires_at_block_height: s.timeout_block_height, - } - } - - ListInvoiceSwaps = async (appUserId: string): Promise => { - 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), - } - } - - RefundInvoiceSwap = async (swapOperationId: string, satPerVByte: number, refundAddress: string, currentHeight: number): Promise<{ published: false, txHex: string, txId: string } | { published: true, txId: string }> => { - this.log("refunding invoice swap", { swapOperationId, satPerVByte, refundAddress, currentHeight }) - const swap = await this.storage.paymentStorage.GetRefundableInvoiceSwap(swapOperationId) - if (!swap) { - throw new Error("Swap not found or already used") - } - const allowEarlyRefund = !!swap.failure_reason - const swapper = this.subSwappers[swap.service_url] - if (!swapper) { - throw new Error("swapper service not found") - } - const result = await swapper.RefundSwap({ - swapId: swap.swap_quote_id, - claimPublicKey: swap.claim_public_key, - currentHeight, - privateKeyHex: swap.ephemeral_private_key, - refundAddress, - swapTree: swap.swap_tree, - timeoutBlockHeight: swap.timeout_block_height, - allowEarlyRefund, - feePerVbyte: satPerVByte, - lockupTxHex: swap.lockup_tx_hex, - }) - if (!result.ok) { - throw new Error(result.error) - } - if (result.publish.done) { - return { published: true, txId: result.publish.txId } - } - return { published: false, txHex: result.publish.txHex, txId: result.publish.txId } - - } - - PayInvoiceSwap = async (appUserId: string, swapOpId: string, satPerVByte: number, payAddress: (address: string, amt: number) => Promise<{ txId: string }>): Promise => { - this.log("paying invoice swap", { appUserId, swapOpId, satPerVByte }) - if (!this.settings.getSettings().swapsSettings.enableSwaps) { - throw new Error("Swaps are not enabled") - } - if (!swapOpId) { - throw new Error("swap operation id is required") - } - if (!satPerVByte) { - throw new Error("sat per v byte is required") - } - const swap = await this.storage.paymentStorage.GetInvoiceSwap(swapOpId, appUserId) - if (!swap) { - throw new Error("swap not found") - } - const swapper = this.subSwappers[swap.service_url] - if (!swapper) { - throw new Error("swapper service not found") - } - if (this.waitingSwaps[swapOpId]) { - throw new Error("swap already in progress") - } - this.waitingSwaps[swapOpId] = true - const data = this.getInvoiceSwapData(swap) - let txId = "" - const close = swapper.SubscribeToInvoiceSwap(data, async (result) => { - if (result.ok) { - await this.storage.paymentStorage.FinalizeInvoiceSwap(swapOpId) - this.log("invoice swap completed", { swapOpId, txId }) - } else { - await this.storage.paymentStorage.FailInvoiceSwap(swapOpId, result.error, txId) - this.log("invoice swap failed", { swapOpId, error: result.error }) - } - }, () => payAddress(swap.address, swap.transaction_amount) - .then(res => { txId = res.txId }) - .catch(err => { close(); this.log("error paying address", err.message || err) })) - } - - ResumeInvoiceSwaps = async () => { - this.log("resuming invoice swaps") - const swaps = await this.storage.paymentStorage.ListUnfinishedInvoiceSwaps() - this.log("resuming", swaps.length, "invoice swaps") - for (const swap of swaps) { - try { - this.resumeInvoiceSwap(swap) - } catch (err: any) { - this.log("error resuming invoice swap", err.message || err) - } - } - } - - - private resumeInvoiceSwap = (swap: InvoiceSwap) => { - // const swap = await this.storage.paymentStorage.GetInvoiceSwap(swapOpId, appUserId) - if (!swap || !swap.tx_id || swap.used) { - throw new Error("swap to resume not found, or does not have a tx id") - } - const swapper = this.subSwappers[swap.service_url] - if (!swapper) { - throw new Error("swapper service not found") - } - const data = this.getInvoiceSwapData(swap) - swapper.SubscribeToInvoiceSwap(data, async (result) => { - if (result.ok) { - await this.storage.paymentStorage.FinalizeInvoiceSwap(swap.swap_operation_id) - this.log("invoice swap completed", { swapOpId: swap.swap_operation_id, txId: swap.tx_id }) - } else { - await this.storage.paymentStorage.FailInvoiceSwap(swap.swap_operation_id, result.error) - this.log("invoice swap failed", { swapOpId: swap.swap_operation_id, error: result.error }) - } - }, () => { throw new Error("swap tx already paid") }) - } - - private getInvoiceSwapData = (swap: InvoiceSwap) => { - return { - createdResponse: { - address: swap.address, - claimPublicKey: swap.claim_public_key, - id: swap.swap_quote_id, - swapTree: swap.swap_tree, - timeoutBlockHeight: swap.timeout_block_height, - expectedAmount: swap.transaction_amount, - }, - info: { - keys: this.GetKeys(swap.ephemeral_private_key), - paymentHash: swap.payment_hash, - } - } - } - - private async getInvoiceSwapQuote(swapper: SubmarineSwaps, appUserId: string, invoice: string): Promise { - const feesRes = await swapper.GetFees() - if (!feesRes.ok) { - throw new Error(feesRes.error) - } - const decoded = await this.lnd.DecodeInvoice(invoice) - const amt = decoded.numSatoshis - const fee = Math.ceil((feesRes.fees.percentage / 100) * amt) + feesRes.fees.minerFees - const res = await swapper.SwapInvoice(invoice) - if (!res.ok) { - throw new Error(res.error) - } - const newSwap = await this.storage.paymentStorage.AddInvoiceSwap({ - app_user_id: appUserId, - swap_quote_id: res.createdResponse.id, - swap_tree: JSON.stringify(res.createdResponse.swapTree), - timeout_block_height: res.createdResponse.timeoutBlockHeight, - ephemeral_public_key: res.pubkey, - ephemeral_private_key: res.privKey, - invoice: invoice, - invoice_amount: amt, - transaction_amount: res.createdResponse.expectedAmount, - swap_fee_sats: fee, - chain_fee_sats: 0, - service_url: swapper.getHttpUrl(), - address: res.createdResponse.address, - claim_public_key: res.createdResponse.claimPublicKey, - payment_hash: decoded.paymentHash, - }) - return { - swap_operation_id: newSwap.swap_operation_id, - invoice: invoice, - invoice_amount_sats: amt, - address: res.createdResponse.address, - transaction_amount_sats: res.createdResponse.expectedAmount, - chain_fee_sats: 0, - service_fee_sats: 0, - service_url: swapper.getHttpUrl(), - swap_fee_sats: fee, - tx_id: newSwap.tx_id, - paid_at_unix: newSwap.paid_at_unix, - expires_at_block_height: newSwap.timeout_block_height, - } - } - - private mapTransactionSwapQuote = (s: TransactionSwap, getServiceFee: (amt: number) => number): Types.TransactionSwapQuote => { - const serviceFee = getServiceFee(s.invoice_amount) - return { - swap_operation_id: s.swap_operation_id, - transaction_amount_sats: s.transaction_amount, - invoice_amount_sats: s.invoice_amount, - chain_fee_sats: s.chain_fee_sats, - service_fee_sats: serviceFee, - swap_fee_sats: s.swap_fee_sats, - expires_at_block_height: s.timeout_block_height, - service_url: s.service_url, - paid_at_unix: s.paid_at_unix, - completed_at_unix: s.completed_at_unix, - } - } - - ListTxSwaps = async (appUserId: string, payments: UserInvoicePayment[], newOp: (p: UserInvoicePayment) => Types.UserOperation | undefined, getServiceFee: (amt: number) => number): Promise => { - const completedSwaps = await this.storage.paymentStorage.ListCompletedTxSwaps(appUserId, payments) - const pendingSwaps = await this.storage.paymentStorage.ListPendingTransactionSwaps(appUserId) - const quotes: Types.TxSwapOperation[] = pendingSwaps.map(s => ({ quote: this.mapTransactionSwapQuote(s, getServiceFee) })) - const swaps: Types.TxSwapOperation[] = completedSwaps.map(s => ({ - quote: this.mapTransactionSwapQuote(s.swap, getServiceFee), - operation_payment: s.payment ? newOp(s.payment) : undefined, - address_paid: s.swap.address_paid, - tx_id: s.swap.tx_id, - failure_reason: s.swap.failure_reason, - })) - return { - swaps: swaps.concat(quotes), - } - } - GetTxSwapQuotes = async (appUserId: string, amt: number, getServiceFee: (decodedAmt: number) => number): Promise => { - if (!this.settings.getSettings().swapsSettings.enableSwaps) { - throw new Error("Swaps are not enabled") - } - const swappers = Object.values(this.revSwappers) - if (swappers.length === 0) { - throw new Error("No swap services available") - } - const res = await Promise.allSettled(swappers.map(sw => this.getTxSwapQuote(sw, appUserId, amt, getServiceFee))) - const failures: string[] = [] - const success: Types.TransactionSwapQuote[] = [] - for (const r of res) { - if (r.status === 'fulfilled') { - success.push(r.value) - } else { - failures.push(r.reason.message ? r.reason.message : r.reason.toString()) - } - } - if (success.length === 0) { - throw new Error(failures.join("\n")) - } - return success - } - - private async getTxSwapQuote(swapper: ReverseSwaps, appUserId: string, amt: number, getServiceFee: (decodedAmt: number) => number): Promise { - this.log("getting transaction swap quote") - const feesRes = await swapper.GetFees() - if (!feesRes.ok) { - throw new Error(feesRes.error) - } - const { claim, lockup } = feesRes.fees.minerFees - const minerFee = claim + lockup - const chainTotal = amt + minerFee - const res = await swapper.SwapTransaction(chainTotal) - if (!res.ok) { - throw new Error(res.error) - } - const decoded = await this.lnd.DecodeInvoice(res.createdResponse.invoice) - const swapFee = decoded.numSatoshis - chainTotal - const serviceFee = getServiceFee(decoded.numSatoshis) - const newSwap = await this.storage.paymentStorage.AddTransactionSwap({ - app_user_id: appUserId, - swap_quote_id: res.createdResponse.id, - swap_tree: JSON.stringify(res.createdResponse.swapTree), - lockup_address: res.createdResponse.lockupAddress, - refund_public_key: res.createdResponse.refundPublicKey, - timeout_block_height: res.createdResponse.timeoutBlockHeight, - invoice: res.createdResponse.invoice, - invoice_amount: decoded.numSatoshis, - transaction_amount: chainTotal, - swap_fee_sats: swapFee, - chain_fee_sats: minerFee, - preimage: res.preimage, - ephemeral_private_key: res.privKey, - ephemeral_public_key: res.pubkey, - service_url: swapper.getHttpUrl(), - }) - return { - swap_operation_id: newSwap.swap_operation_id, - swap_fee_sats: swapFee, - invoice_amount_sats: decoded.numSatoshis, - transaction_amount_sats: amt, - chain_fee_sats: minerFee, - service_fee_sats: serviceFee, - service_url: swapper.getHttpUrl(), - expires_at_block_height: res.createdResponse.timeoutBlockHeight, - paid_at_unix: newSwap.paid_at_unix, - completed_at_unix: newSwap.completed_at_unix, - } - } - - async PayAddrWithSwap(appUserId: string, swapOpId: string, address: string, payInvoice: (invoice: string, amt: number) => Promise) { - if (!this.settings.getSettings().swapsSettings.enableSwaps) { - throw new Error("Swaps are not enabled") - } - this.log("paying address with swap", { appUserId, swapOpId, address }) - if (!swapOpId) { - throw new Error("request a swap quote before paying an external address") - } - const txSwap = await this.storage.paymentStorage.GetTransactionSwap(swapOpId, appUserId) - if (!txSwap) { - throw new Error("swap quote not found") - } - const info = await this.lnd.GetInfo() - if (info.blockHeight >= txSwap.timeout_block_height) { - throw new Error("swap timeout") - } - const swapper = this.revSwappers[txSwap.service_url] - if (!swapper) { - throw new Error("swapper service not found") - } - const keys = this.GetKeys(txSwap.ephemeral_private_key) - const data: TransactionSwapData = { - createdResponse: { - id: txSwap.swap_quote_id, - invoice: txSwap.invoice, - lockupAddress: txSwap.lockup_address, - refundPublicKey: txSwap.refund_public_key, - swapTree: txSwap.swap_tree, - timeoutBlockHeight: txSwap.timeout_block_height, - onchainAmount: txSwap.transaction_amount, - }, - info: { - destinationAddress: address, - keys, - chainFee: txSwap.chain_fee_sats, - preimage: Buffer.from(txSwap.preimage, 'hex'), - } - } - // the swap and the invoice payment are linked, swap will not start until the invoice payment is started, and will not complete once the invoice payment is completed - let swapResult = { ok: false, error: "swap never completed" } as { ok: true, txId: string } | { ok: false, error: string } - swapper.SubscribeToTransactionSwap(data, result => { - swapResult = result - }) - try { - await this.storage.paymentStorage.SetTransactionSwapPaid(swapOpId) - await payInvoice(txSwap.invoice, txSwap.invoice_amount) - if (!swapResult.ok) { - this.log("invoice payment successful, but swap failed") - await this.storage.paymentStorage.FailTransactionSwap(swapOpId, address, swapResult.error) - throw new Error(swapResult.error) - } - this.log("swap completed successfully") - await this.storage.paymentStorage.FinalizeTransactionSwap(swapOpId, address, swapResult.txId) - } catch (err: any) { - if (swapResult.ok) { - this.log("failed to pay swap invoice, but swap completed successfully", swapResult.txId) - await this.storage.paymentStorage.FailTransactionSwap(swapOpId, address, err.message) - } else { - this.log("failed to pay swap invoice and swap failed", swapResult.error) - await this.storage.paymentStorage.FailTransactionSwap(swapOpId, address, swapResult.error) - } - throw err - } - const networkFeesTotal = txSwap.chain_fee_sats + txSwap.swap_fee_sats - return { - txId: swapResult.txId, - network_fee: networkFeesTotal - } - } -} \ No newline at end of file diff --git a/src/services/main/adminManager.ts b/src/services/main/adminManager.ts index dbde290d..294635ed 100644 --- a/src/services/main/adminManager.ts +++ b/src/services/main/adminManager.ts @@ -5,50 +5,9 @@ import Storage from "../storage/index.js"; import * as Types from '../../../proto/autogenerated/ts/types.js' import LND from "../lnd/lnd.js"; import SettingsManager from "./settingsManager.js"; -import { Swaps } from "../lnd/swaps/swaps.js"; -import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"; -import { TrackedProvider } from "../storage/entity/TrackedProvider.js"; -import { NodeInfo } from "../lnd/settings.js"; -import { Invoice, Payment, OutputDetail, Transaction, Payment_PaymentStatus, Invoice_InvoiceState } from "../../../proto/lnd/lightning.js"; -import { LiquidityProvider } from "./liquidityProvider.js"; -/* type TrackedOperation = { - ts: number - amount: number - type: 'user' | 'root' -} - -type AssetOperation = { - ts: number - amount: number - tracked?: TrackedOperation -} -type TrackedLndProvider = { - confirmedBalance: number - unconfirmedBalance: number - channelsBalace: number - payments: AssetOperation[] - invoices: AssetOperation[] - incomingTx: AssetOperation[] - outgoingTx: AssetOperation[] -} -type LndAssetProvider = { - pubkey: string - tracked?: TrackedLndProvider -} -type TrackedLiquidityProvider = { - balance: number - payments: AssetOperation[] - invoices: AssetOperation[] -} -type ProviderAssetProvider = { - pubkey: string - tracked?: TrackedLiquidityProvider -} */ -const ROOT_OP = Types.TrackedOperationType.ROOT -const USER_OP = Types.TrackedOperationType.USER +import { Swaps } from "../lnd/swaps.js"; export class AdminManager { settings: SettingsManager - liquidityProvider: LiquidityProvider | null = null storage: Storage log = getLogger({ component: "adminManager" }) adminNpub = "" @@ -81,10 +40,6 @@ export class AdminManager { this.start() } - attachLiquidityProvider(liquidityProvider: LiquidityProvider) { - this.liquidityProvider = liquidityProvider - } - attachNostrReset(f: () => Promise) { this.nostrReset = f } @@ -305,64 +260,15 @@ export class AdminManager { } } - async ListAdminInvoiceSwaps(): Promise { - return this.swaps.ListInvoiceSwaps("admin") - } - - async GetAdminInvoiceSwapQuotes(req: Types.InvoiceSwapRequest): Promise { - const invoice = await this.lnd.NewInvoice(req.amount_sats, "Admin Swap", defaultInvoiceExpiry, { useProvider: false, from: 'system' }) - const quotes = await this.swaps.GetInvoiceSwapQuotes("admin", invoice.payRequest) - return { quotes } - } - - async PayAdminInvoiceSwap(req: Types.PayAdminInvoiceSwapRequest): Promise { - const resolvedTxId = await new Promise(res => { - this.swaps.PayInvoiceSwap("admin", req.swap_operation_id, req.sat_per_v_byte, async (addr, amt) => { - const tx = await this.lnd.PayAddress(addr, amt, req.sat_per_v_byte, "", { useProvider: false, from: 'system' }) - this.log("paid admin invoice swap", { swapOpId: req.swap_operation_id, txId: tx.txid }) - await this.storage.metricsStorage.AddRootOperation("chain_payment", tx.txid, amt, true) - - // Fetch the full transaction hex for potential refunds - let lockupTxHex: string | undefined - let chainFeeSats = 0 - try { - const txDetails = await this.lnd.GetTx(tx.txid) - chainFeeSats = Number(txDetails.totalFees) - lockupTxHex = txDetails.rawTxHex - } catch (err: any) { - this.log("Warning: Could not fetch transaction hex for refund purposes:", err.message) - } - - 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 }) - res(tx.txid) - return { txId: tx.txid } - }) - }) - return { tx_id: resolvedTxId } - } - - async RefundAdminInvoiceSwap(req: Types.RefundAdminInvoiceSwapRequest): Promise { - const info = await this.lnd.GetInfo() - const currentHeight = info.blockHeight - const address = await this.lnd.NewAddress(Types.AddressType.WITNESS_PUBKEY_HASH, { useProvider: false, from: 'system' }) - const result = await this.swaps.RefundInvoiceSwap(req.swap_operation_id, req.sat_per_v_byte, address.address, currentHeight) - if (result.published) { - return { tx_id: result.txId } - } - await this.lnd.PublishTransaction(result.txHex) - return { tx_id: result.txId } - } - - async ListAdminTxSwaps(): Promise { - return this.swaps.ListTxSwaps("admin", [], p => undefined, amt => 0) + async ListAdminSwaps(): Promise { + return this.swaps.ListSwaps("admin", [], p => undefined, amt => 0) } async GetAdminTransactionSwapQuotes(req: Types.TransactionSwapRequest): Promise { const quotes = await this.swaps.GetTxSwapQuotes("admin", req.transaction_amount_sats, () => 0) return { quotes } } - async PayAdminTransactionSwap(req: Types.PayAdminTransactionSwapRequest): Promise { + async PayAdminTransactionSwap(req: Types.PayAdminTransactionSwapRequest): Promise { const routingFloor = this.settings.getSettings().lndSettings.routingFeeFloor const routingLimit = this.settings.getSettings().lndSettings.routingFeeLimitBps / 10000 @@ -376,222 +282,6 @@ export class AdminManager { network_fee: swap.network_fee, } } - - async GetAssetsAndLiabilities(req: Types.AssetsAndLiabilitiesReq): Promise { - const providers = await this.storage.liquidityStorage.GetTrackedProviders() - - const lnds: Types.LndAssetProvider[] = [] - const liquidityProviders: Types.LiquidityAssetProvider[] = [] - for (const provider of providers) { - if (provider.provider_type === 'lnd') { - const lndEntry = await this.GetLndAssetsAndLiabilities(req, provider) - lnds.push(lndEntry) - } else if (provider.provider_type === 'lnPub') { - const liquidityEntry = await this.GetProviderAssetsAndLiabilities(req, provider) - liquidityProviders.push(liquidityEntry) - } - } - const usersBalance = await this.storage.paymentStorage.GetTotalUsersBalance(true) - return { - users_balance: usersBalance, - lnds, - liquidity_providers: liquidityProviders, - } - } - - async GetProviderAssetsAndLiabilities(req: Types.AssetsAndLiabilitiesReq, provider: TrackedProvider): Promise { - if (!this.liquidityProvider) { - throw new Error("liquidity provider not attached") - } - if (this.liquidityProvider.GetProviderPubkey() !== provider.provider_pubkey) { - return { pubkey: provider.provider_pubkey, tracked: undefined } - } - const providerOps = await this.liquidityProvider.GetOperations(req.limit_providers || 100) - // we only care about invoices cuz they are the only ops we can generate with a provider - const invoices: Types.AssetOperation[] = [] - const payments: Types.AssetOperation[] = [] - for (const op of providerOps.latestIncomingInvoiceOperations.operations) { - const assetOp = await this.GetProviderInvoiceAssetOperation(op) - invoices.push(assetOp) - } - for (const op of providerOps.latestOutgoingInvoiceOperations.operations) { - const assetOp = await this.GetProviderPaymentAssetOperation(op) - payments.push(assetOp) - } - const balance = await this.liquidityProvider.GetUserState() - return { - pubkey: provider.provider_pubkey, - tracked: { - balance: balance.status === 'OK' ? balance.balance : 0, - payments, - invoices, - } - } - } - - async GetProviderInvoiceAssetOperation(op: Types.UserOperation): Promise { - const ts = Number(op.paidAtUnix) - const amount = Number(op.amount) - const invoice = op.identifier - const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(invoice) - if (userInvoice) { - const tracked: Types.TrackedOperation = { ts: userInvoice.paid_at_unix, amount: userInvoice.paid_amount, type: USER_OP } - return { ts, amount, tracked } - } - const rootOp = await this.storage.metricsStorage.GetRootOperation("invoice", invoice) - if (rootOp) { - const tracked: Types.TrackedOperation = { ts: rootOp.at_unix, amount: rootOp.operation_amount, type: ROOT_OP } - return { ts, amount, tracked } - } - return { ts, amount, tracked: undefined } - } - - async GetProviderPaymentAssetOperation(op: Types.UserOperation): Promise { - const ts = Number(op.paidAtUnix) - const amount = Number(op.amount) - const invoice = op.identifier - const userInvoice = await this.storage.paymentStorage.GetPaymentOwner(invoice) - if (userInvoice) { - const tracked: Types.TrackedOperation = { ts: userInvoice.paid_at_unix, amount: userInvoice.paid_amount, type: USER_OP } - return { ts, amount, tracked } - } - const rootOp = await this.storage.metricsStorage.GetRootOperation("invoice_payment", invoice) - if (rootOp) { - const tracked: Types.TrackedOperation = { ts: rootOp.at_unix, amount: rootOp.operation_amount, type: ROOT_OP } - return { ts, amount, tracked } - } - return { ts, amount, tracked: undefined } - } - - async GetLndAssetsAndLiabilities(req: Types.AssetsAndLiabilitiesReq, provider: TrackedProvider): Promise { - const info = await this.lnd.GetInfo() - if (provider.provider_pubkey !== info.identityPubkey) { - return { pubkey: provider.provider_pubkey, tracked: undefined } - } - - const latestLndPayments = await this.lnd.GetAllPayments(req.limit_payments || 50) - const payments: Types.AssetOperation[] = [] - for (const payment of latestLndPayments.payments) { - if (payment.status !== Payment_PaymentStatus.SUCCEEDED) { - continue - } - const assetOp = await this.GetPaymentAssetOperation(payment) - payments.push(assetOp) - } - const invoices: Types.AssetOperation[] = [] - const paidInvoices = await this.lnd.GetAllInvoices(req.limit_invoices || 100) - for (const invoiceEntry of paidInvoices.invoices) { - if (invoiceEntry.state !== Invoice_InvoiceState.SETTLED) { - continue - } - const assetOp = await this.GetInvoiceAssetOperation(invoiceEntry) - invoices.push(assetOp) - } - const latestLndTransactions = await this.lnd.GetTransactions(info.blockHeight) - const txOuts: Types.AssetOperation[] = [] - const txIns: Types.AssetOperation[] = [] - for (const transaction of latestLndTransactions.transactions) { - for (const output of transaction.outputDetails) { - if (output.isOurAddress) { - const assetOp = await this.GetTxOutAssetOperation(transaction, output) - txOuts.push(assetOp) - } - } - // we only produce TXs with a single output - const input = transaction.previousOutpoints.find(p => p.isOurOutput) - if (input) { - const assetOp = await this.GetTxInAssetOperation(transaction) - txIns.push(assetOp) - } - } - const balance = await this.lnd.GetBalance() - const channelsBalance = balance.channelsBalance.reduce((acc, c) => acc + Number(c.localBalanceSats), 0) - return { - pubkey: provider.provider_pubkey, - tracked: { - confirmed_balance: Number(balance.confirmedBalance), - unconfirmed_balance: Number(balance.unconfirmedBalance), - channels_balance: channelsBalance, - payments, - invoices, - incoming_tx: txOuts, // tx outputs, are incoming sats - outgoing_tx: txIns, // tx inputs, are outgoing sats - } - } - } - - async GetPaymentAssetOperation(payment: Payment): Promise { - const invoice = payment.paymentRequest - const userInvoice = await this.storage.paymentStorage.GetPaymentOwner(invoice) - const ts = Number(payment.creationTimeNs / (BigInt(1000_000_000))) - const amount = Number(payment.valueSat) - if (userInvoice) { - const tracked: Types.TrackedOperation = { ts: userInvoice.paid_at_unix, amount: userInvoice.paid_amount, type: USER_OP } - return { ts, amount, tracked } - } - const rootOp = await this.storage.metricsStorage.GetRootOperation("invoice_payment", invoice) - if (rootOp) { - const tracked: Types.TrackedOperation = { ts: rootOp.at_unix, amount: rootOp.operation_amount, type: ROOT_OP } - return { ts, amount, tracked } - } - return { ts, amount, tracked: undefined } - } - - async GetInvoiceAssetOperation(invoiceEntry: Invoice): Promise { - const invoice = invoiceEntry.paymentRequest - const ts = Number(invoiceEntry.settleDate) - const amount = Number(invoiceEntry.amtPaidSat) - const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(invoice) - if (userInvoice) { - const tracked: Types.TrackedOperation = { ts: userInvoice.paid_at_unix, amount: userInvoice.paid_amount, type: USER_OP } - return { ts, amount, tracked } - } - const rootOp = await this.storage.metricsStorage.GetRootOperation("invoice", invoice) - if (rootOp) { - const tracked: Types.TrackedOperation = { ts: rootOp.at_unix, amount: rootOp.operation_amount, type: ROOT_OP } - return { ts, amount, tracked } - } - return { ts, amount, tracked: undefined } - } - - async GetTxInAssetOperation(tx: Transaction): Promise { - const ts = Number(tx.timeStamp) - const amount = Number(tx.amount) - const userOp = await this.storage.paymentStorage.GetTxHashPaymentOwner(tx.txHash) - if (userOp) { - // user transaction payments are actually deprecated from lnd, but we keep this for consstency - const tracked: Types.TrackedOperation = { ts: userOp.paid_at_unix, amount: userOp.paid_amount, type: USER_OP } - return { ts, amount, tracked } - } - const rootOp = await this.storage.metricsStorage.GetRootOperation("chain_payment", tx.txHash) - if (rootOp) { - const tracked: Types.TrackedOperation = { ts: rootOp.at_unix, amount: rootOp.operation_amount, type: ROOT_OP } - return { ts, amount, tracked } - } - return { ts, amount, tracked: undefined } - } - - async GetTxOutAssetOperation(tx: Transaction, output: OutputDetail): Promise { - const ts = Number(tx.timeStamp) - const amount = Number(output.amount) - const outputIndex = Number(output.outputIndex) - const userOp = await this.storage.paymentStorage.GetAddressReceivingTransactionOwner(output.address, tx.txHash) - if (userOp) { - const tracked: Types.TrackedOperation = { ts: userOp.paid_at_unix, amount: userOp.paid_amount, type: USER_OP } - return { ts, amount, tracked } - } - const rootOp = await this.storage.metricsStorage.GetRootAddressTransaction(output.address, tx.txHash, outputIndex) - if (rootOp) { - const tracked: Types.TrackedOperation = { ts: rootOp.at_unix, amount: rootOp.operation_amount, type: ROOT_OP } - return { ts, amount, tracked } - } - return { ts, amount, tracked: undefined } - } - - async BumpTx(req: Types.BumpTx): Promise { - await this.lnd.BumpFee(req.txid, req.output_index, req.sat_per_vbyte) - } - } const getDataPath = (dataDir: string, dataPath: string) => { diff --git a/src/services/main/appUserManager.ts b/src/services/main/appUserManager.ts index b9bf8742..9db8b5e6 100644 --- a/src/services/main/appUserManager.ts +++ b/src/services/main/appUserManager.ts @@ -66,7 +66,7 @@ export default class { const appUser = await this.storage.applicationStorage.GetAppUserFromUser(app, user.user_id) if (!appUser) { - throw new Error("app user not found") + throw new Error(`app user ${ctx.user_id} not found`) // TODO: fix logs doxing } const nostrSettings = this.settings.getSettings().nostrRelaySettings const { max, serviceFeeFloor, serviceFeeBps } = this.applicationManager.paymentManager.GetMaxPayableInvoice(user.balance_sats) @@ -82,8 +82,7 @@ export default class { ndebit: ndebitEncode({ pubkey: app.nostr_public_key!, pointer: appUser.identifier, relay: nostrSettings.relays[0] }), nmanage: nmanageEncode({ pubkey: app.nostr_public_key!, pointer: appUser.identifier, relay: nostrSettings.relays[0] }), callback_url: appUser.callback_url, - bridge_url: this.settings.getSettings().serviceSettings.bridgeUrl, - topic_id: appUser.topic_id + bridge_url: this.settings.getSettings().serviceSettings.bridgeUrl } } @@ -132,12 +131,12 @@ export default class { } this.log("Found", toDelete.length, "inactive users to delete") - await this.LockUsers(toDelete.map(u => u.userId)) + // await this.RemoveUsers(toDelete) } async CleanupNeverActiveUsers() { this.log("Cleaning up never active users") - const inactiveUsers = await this.storage.userStorage.GetInactiveUsers(90) + const inactiveUsers = await this.storage.userStorage.GetInactiveUsers(30) const toDelete: { userId: string, appUserIds: string[] }[] = [] for (const u of inactiveUsers) { const user = await this.storage.userStorage.GetUser(u.user_id) @@ -161,26 +160,13 @@ export default class { } this.log("Found", toDelete.length, "never active users to delete") - await this.RemoveUsers(toDelete) - } - - async LockUsers(toLock: string[]) { - this.log("Locking", toLock.length, "users") - for (const userId of toLock) { - await this.storage.userStorage.BanUser(userId) - } - this.log("Locked users") + // await this.RemoveUsers(toDelete) TODO: activate deletion } async RemoveUsers(toDelete: { userId: string, appUserIds: string[] }[]) { this.log("Deleting", toDelete.length, "inactive users") for (let i = 0; i < toDelete.length; i++) { const { userId, appUserIds } = toDelete[i] - const user = await this.storage.userStorage.FindUser(userId) - if (!user || user.balance_sats > 0) { - if (user) this.log("Skipping user", userId, "has balance", user.balance_sats) - continue - } this.log("Deleting user", userId, "progress", i + 1, "/", toDelete.length) await this.storage.StartTransaction(async tx => { for (const appUserId of appUserIds) { @@ -188,18 +174,13 @@ export default class { await this.storage.offerStorage.DeleteUserOffers(appUserId, tx) await this.storage.debitStorage.RemoveUserDebitAccess(appUserId, tx) await this.storage.applicationStorage.RemoveAppUserDevices(appUserId, tx) + } await this.storage.paymentStorage.RemoveUserInvoices(userId, tx) await this.storage.productStorage.RemoveUserProducts(userId, tx) await this.storage.paymentStorage.RemoveUserEphemeralKeys(userId, tx) - await this.storage.paymentStorage.RemoveUserInvoicePayments(userId, tx) - await this.storage.paymentStorage.RemoveUserTransactionPayments(userId, tx) - await this.storage.paymentStorage.RemoveUserToUserPayments(userId, tx) - await this.storage.paymentStorage.RemoveUserReceivingAddresses(userId, tx) - await this.storage.userStorage.DeleteUserAccess(userId, tx) - await this.storage.applicationStorage.RemoveAppUsersAndBaseUsers(appUserIds, userId, tx) }) } this.log("Cleaned up inactive users") } -} +} \ No newline at end of file diff --git a/src/services/main/applicationManager.ts b/src/services/main/applicationManager.ts index ecfc7b85..aaafd8a7 100644 --- a/src/services/main/applicationManager.ts +++ b/src/services/main/applicationManager.ts @@ -169,8 +169,7 @@ export default class { ndebit: ndebitEncode({ pubkey: app.nostr_public_key!, pointer: u.identifier, relay: nostrSettings.relays[0] }), nmanage: nmanageEncode({ pubkey: app.nostr_public_key!, pointer: u.identifier, relay: nostrSettings.relays[0] }), callback_url: u.callback_url, - bridge_url: this.settings.getSettings().serviceSettings.bridgeUrl, - topic_id: u.topic_id + bridge_url: this.settings.getSettings().serviceSettings.bridgeUrl }, max_withdrawable: max @@ -228,8 +227,7 @@ export default class { ndebit: ndebitEncode({ pubkey: app.nostr_public_key!, pointer: user.identifier, relay: nostrSettings.relays[0] }), nmanage: nmanageEncode({ pubkey: app.nostr_public_key!, pointer: user.identifier, relay: nostrSettings.relays[0] }), callback_url: user.callback_url, - bridge_url: this.settings.getSettings().serviceSettings.bridgeUrl, - topic_id: user.topic_id + bridge_url: this.settings.getSettings().serviceSettings.bridgeUrl }, } } diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 81de5ada..3d885681 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -72,7 +72,6 @@ export default class { this.unlocker = unlocker const updateProviderBalance = (b: number) => this.storage.liquidityStorage.IncrementTrackedProviderBalance('lnPub', settings.getSettings().liquiditySettings.liquidityProviderPub, b) this.liquidityProvider = new LiquidityProvider(() => this.settings.getSettings().liquiditySettings, this.utils, this.invoicePaidCb, updateProviderBalance) - adminManager.attachLiquidityProvider(this.liquidityProvider) this.rugPullTracker = new RugPullTracker(this.storage, this.liquidityProvider) const lndGetSettings = () => ({ lndSettings: settings.getSettings().lndSettings, @@ -162,23 +161,19 @@ export default class { NewBlockHandler = async (height: number, skipMetrics?: boolean) => { let confirmed: (PendingTx & { confs: number; })[] let log = getLogger({}) - log("NewBlockHandler called", JSON.stringify({ height, skipMetrics })) this.storage.paymentStorage.DeleteExpiredTransactionSwaps(height) .catch(err => log(ERROR, "failed to delete expired transaction swaps", err.message || err)) - this.storage.paymentStorage.DeleteExpiredInvoiceSwaps(height) - .catch(err => log(ERROR, "failed to delete expired invoice swaps", err.message || err)) try { const balanceEvents = await this.paymentManager.GetLndBalance() if (!skipMetrics) { await this.metricsManager.NewBlockCb(height, balanceEvents) } - confirmed = await this.paymentManager.CheckNewlyConfirmedTxs() + confirmed = await this.paymentManager.CheckNewlyConfirmedTxs(height) await this.liquidityManager.onNewBlock() } catch (err: any) { log(ERROR, "failed to check transactions after new block", err.message || err) return } - log("NewBlockHandler new confirmed transactions", confirmed.length) await Promise.all(confirmed.map(async c => { if (c.type === 'outgoing') { await this.storage.paymentStorage.UpdateUserTransactionPayment(c.tx.serial_id, { confs: c.confs }) @@ -213,7 +208,6 @@ export default class { addressPaidCb: AddressPaidCb = (txOutput, address, amount, used, broadcastHeight) => { return this.storage.StartTransaction(async tx => { - getLogger({})("addressPaidCb called", JSON.stringify({ txOutput, address, amount, used, broadcastHeight })) // On-chain payments not supported when bypass is enabled if (this.liquidityProvider.getSettings().useOnlyLiquidityProvider) { getLogger({})("addressPaidCb called but USE_ONLY_LIQUIDITY_PROVIDER is enabled, ignoring") @@ -425,36 +419,13 @@ export default class { if (devices.length === 0 || !app.nostr_public_key || !app.nostr_private_key || !appUser.nostr_public_key) { return } - const tokens = devices.map(d => d.firebase_messaging_token) const ck = nip44.getConversationKey(Buffer.from(app.nostr_private_key, 'hex'), appUser.nostr_public_key) - - let payloadToEncrypt: Types.PushNotificationPayload; - if (op.inbound) { - payloadToEncrypt = { - data: { - type: Types.PushNotificationPayload_data_type.RECEIVED_OPERATION, - received_operation: op - } - } - } else { - payloadToEncrypt = { - data: { - type: Types.PushNotificationPayload_data_type.SENT_OPERATION, - sent_operation: op - } - } - } - const j = JSON.stringify(payloadToEncrypt) + const j = JSON.stringify(op) const encrypted = nip44.encrypt(j, ck) - - const envelope: Types.PushNotificationEnvelope = { - topic_id: appUser.topic_id, - app_npub_hex: app.nostr_public_key, - encrypted_payload: encrypted - } + const encryptedData: { encrypted: string, app_npub_hex: string } = { encrypted, app_npub_hex: app.nostr_public_key } const notification: ShockPushNotification = { - message: JSON.stringify(envelope), + message: JSON.stringify(encryptedData), body, title } diff --git a/src/services/main/init.ts b/src/services/main/init.ts index 946061fb..3cbba602 100644 --- a/src/services/main/init.ts +++ b/src/services/main/init.ts @@ -11,7 +11,7 @@ import { AdminManager } from "./adminManager.js" import SettingsManager from "./settingsManager.js" import { LoadStorageSettingsFromEnv } from "../storage/index.js" import { NostrSender } from "../nostr/sender.js" -import { Swaps } from "../lnd/swaps/swaps.js" +import { Swaps } from "../lnd/swaps.js" export type AppData = { privateKey: string; publicKey: string; @@ -79,7 +79,6 @@ export const initMainHandler = async (log: PubLogger, settingsManager: SettingsM await mainHandler.paymentManager.CleanupOldUnpaidInvoices() await mainHandler.appUserManager.CleanupInactiveUsers() await mainHandler.appUserManager.CleanupNeverActiveUsers() - await swaps.ResumeInvoiceSwaps() await mainHandler.paymentManager.watchDog.Start() return { mainHandler, apps, localProviderClient, wizard, adminManager } } diff --git a/src/services/main/liquidityProvider.ts b/src/services/main/liquidityProvider.ts index a39f86a6..1f8fe2dd 100644 --- a/src/services/main/liquidityProvider.ts +++ b/src/services/main/liquidityProvider.ts @@ -277,14 +277,14 @@ export class LiquidityProvider { return res } - GetOperations = async (max = 200) => { + GetOperations = async () => { if (!this.IsReady()) { throw new Error("liquidity provider is not ready yet, disabled or unreachable") } const res = await this.client.GetUserOperations({ latestIncomingInvoice: { ts: 0, id: 0 }, latestOutgoingInvoice: { ts: 0, id: 0 }, latestIncomingTx: { ts: 0, id: 0 }, latestOutgoingTx: { ts: 0, id: 0 }, latestIncomingUserToUserPayment: { ts: 0, id: 0 }, - latestOutgoingUserToUserPayment: { ts: 0, id: 0 }, max_size: max + latestOutgoingUserToUserPayment: { ts: 0, id: 0 }, max_size: 200 }) if (res.status === 'ERROR') { this.log("error getting operations", res.reason) diff --git a/src/services/main/paymentManager.ts b/src/services/main/paymentManager.ts index 7d96898d..c68020dc 100644 --- a/src/services/main/paymentManager.ts +++ b/src/services/main/paymentManager.ts @@ -18,7 +18,7 @@ import { LiquidityManager } from './liquidityManager.js' import { Utils } from '../helpers/utilsWrapper.js' import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js' import SettingsManager from './settingsManager.js' -import { Swaps } from '../lnd/swaps/swaps.js' +import { Swaps, TransactionSwapData } from '../lnd/swaps.js' import { Transaction, OutputDetail } from '../../../proto/lnd/lightning.js' import { LndAddress } from '../lnd/lnd.js' import Metrics from '../metrics/index.js' @@ -201,11 +201,24 @@ export default class { } else { log("no missed chain transactions found") } + await this.reprocessStuckPendingTx(log, currentHeight) } catch (err: any) { log(ERROR, "failed to check for missed chain transactions:", err.message || err) } } + reprocessStuckPendingTx = async (log: PubLogger, currentHeight: number) => { + const { incoming } = await this.storage.paymentStorage.GetPendingTransactions() + const found = incoming.find(t => t.broadcast_height < currentHeight - 100) + if (found) { + log("found a possibly stuck pending transaction, reprocessing with full transaction history") + // There is a pending transaction more than 100 blocks old, this is likely a transaction + // that has a broadcast height higher than it actually is, so its not getting picked up when being processed + // by calling new block cb with height of 1, we make sure that even if the transaction has a newer height, it will still be processed + await this.newBlockCb(1, true) + } + } + private async getLatestTransactions(log: PubLogger): Promise<{ txs: Transaction[], currentHeight: number, lndPubkey: string, startHeight: number }> { const lndInfo = await this.lnd.GetInfo() const lndPubkey = lndInfo.identityPubkey @@ -260,14 +273,14 @@ export default class { private async processRootAddressOutput(output: OutputDetail, tx: Transaction, addresses: LndAddress[], log: PubLogger): Promise { const addr = addresses.find(a => a.address === output.address) if (!addr) { - throw new Error(`root address ${output.address} not found in list of addresses`) + throw new Error(`address ${output.address} not found in list of addresses`) } if (addr.change) { log(`ignoring change address ${output.address}`) return false } const outputIndex = Number(output.outputIndex) - const existingRootOp = await this.storage.metricsStorage.GetRootAddressTransaction(output.address, tx.txHash, outputIndex) + const existingRootOp = await this.metrics.GetRootAddressTransaction(output.address, tx.txHash, outputIndex) if (existingRootOp) { return false } @@ -289,11 +302,8 @@ export default class { const amount = Number(output.amount) const outputIndex = Number(output.outputIndex) log(`processing missed chain tx: address=${output.address}, txHash=${tx.txHash}, amount=${amount}, outputIndex=${outputIndex}`) - try { - await this.addressPaidCb({ hash: tx.txHash, index: outputIndex }, output.address, amount, 'lnd', startHeight) - } catch (err: any) { - log(ERROR, "failed to process user address output:", err.message || err) - } + this.addressPaidCb({ hash: tx.txHash, index: outputIndex }, output.address, amount, 'lnd', startHeight) + .catch(err => log(ERROR, "failed to process user address output:", err.message || err)) return true } @@ -595,15 +605,9 @@ export default class { async PayInternalAddress(ctx: Types.UserContext, req: Types.PayAddressRequest): Promise { this.log("paying internal address") - let amount = req.amountSats if (req.swap_operation_id) { - const swap = await this.storage.paymentStorage.GetTransactionSwap(req.swap_operation_id, ctx.app_user_id) - amount = amount > 0 ? amount : swap?.invoice_amount || 0 await this.storage.paymentStorage.DeleteTransactionSwap(req.swap_operation_id) } - if (amount <= 0) { - throw new Error("invalid tx amount") - } const { blockHeight } = await this.lnd.GetInfo() const app = await this.storage.applicationStorage.GetApplication(ctx.app_id) const isManagedUser = ctx.user_id !== app.owner.user_id @@ -630,13 +634,11 @@ export default class { } } - async ListTxSwaps(ctx: Types.UserContext): Promise { - console.log("listing tx swaps", { appUserId: ctx.app_user_id }) - const payments = await this.storage.paymentStorage.ListTxSwapPayments(ctx.app_user_id) - console.log("payments", payments.length) + async ListSwaps(ctx: Types.UserContext): Promise { + const payments = await this.storage.paymentStorage.ListSwapPayments(ctx.app_user_id) const app = await this.storage.applicationStorage.GetApplication(ctx.app_id) const isManagedUser = ctx.user_id !== app.owner.user_id - return this.swaps.ListTxSwaps(ctx.app_user_id, payments, p => { + return this.swaps.ListSwaps(ctx.app_user_id, payments, p => { const opId = `${Types.UserOperationType.OUTGOING_TX}-${p.serial_id}` return this.newInvoicePaymentOperation({ amount: p.paid_amount, confirmed: p.paid_at_unix !== 0, invoice: p.invoice, opId, networkFee: p.routing_fees, serviceFee: p.service_fees, paidAtUnix: p.paid_at_unix }) }, amt => this.getSendServiceFee(Types.UserOperationType.OUTGOING_INVOICE, amt, isManagedUser)) @@ -971,38 +973,29 @@ export default class { return { amount: payment.paid_amount, fees: payment.service_fees } } - private async getTxConfs(txHash: string): Promise { - try { - const info = await this.lnd.GetTx(txHash) - const { numConfirmations: confs, amount: amt } = info - if (confs > 2 || (amt <= confInTwo && confs > 1) || (amt <= confInOne && confs > 0)) { - return confs - } - } catch (err: any) { - getLogger({})("failed to get tx info", err.message || err) - } - return 0 - } - - async CheckNewlyConfirmedTxs() { + async CheckNewlyConfirmedTxs(height: number) { const pending = await this.storage.paymentStorage.GetPendingTransactions() - let log = getLogger({}) - log("CheckNewlyConfirmedTxs ", pending.incoming.length, "incoming", pending.outgoing.length, "outgoing") - const confirmedIncoming: (PendingTx & { confs: number })[] = [] - const confirmedOutgoing: (PendingTx & { confs: number })[] = [] - for (const tx of pending.incoming) { - const confs = await this.getTxConfs(tx.tx_hash) - if (confs > 0) { - confirmedIncoming.push({ type: "incoming", tx: tx, confs }) - } + let lowestHeight = height + const map: Record = {} + + const checkTx = (t: PendingTx) => { + if (t.tx.broadcast_height < lowestHeight) { lowestHeight = t.tx.broadcast_height } + map[t.tx.tx_hash] = t } - for (const tx of pending.outgoing) { - const confs = await this.getTxConfs(tx.tx_hash) - if (confs > 0) { - confirmedOutgoing.push({ type: "outgoing", tx: tx, confs }) + pending.incoming.forEach(t => checkTx({ type: "incoming", tx: t })) + pending.outgoing.forEach(t => checkTx({ type: "outgoing", tx: t })) + const { transactions } = await this.lnd.GetTransactions(lowestHeight) + const newlyConfirmedTxs = transactions.map(tx => { + const { txHash, numConfirmations: confs, amount: amt } = tx + const t = map[txHash] + if (!t || confs === 0) { + return } - } - return confirmedIncoming.concat(confirmedOutgoing) + if (confs > 2 || (amt <= confInTwo && confs > 1) || (amt <= confInOne && confs > 0)) { + return { ...t, confs } + } + }) + return newlyConfirmedTxs.filter(t => t !== undefined) as (PendingTx & { confs: number })[] } async CleanupOldUnpaidInvoices() { diff --git a/src/services/main/sanityChecker.ts b/src/services/main/sanityChecker.ts index cb0ecb75..6ef7419a 100644 --- a/src/services/main/sanityChecker.ts +++ b/src/services/main/sanityChecker.ts @@ -226,7 +226,7 @@ export default class SanityChecker { async VerifyEventsLog() { this.events = await this.storage.eventsLog.GetAllLogs() - this.invoices = (await this.lnd.GetAllInvoices(1000)).invoices + this.invoices = (await this.lnd.GetAllPaidInvoices(1000)).invoices this.payments = (await this.lnd.GetAllPayments(1000)).payments this.incrementSources = {} diff --git a/src/services/main/watchdog.ts b/src/services/main/watchdog.ts index d9d585ba..778e09ce 100644 --- a/src/services/main/watchdog.ts +++ b/src/services/main/watchdog.ts @@ -29,7 +29,6 @@ export class Watchdog { ready = false interval: NodeJS.Timer; lndPubKey: string; - lastHandlerRootOpsAtUnix = 0 constructor(settings: SettingsManager, liquidityManager: LiquidityManager, lnd: LND, storage: Storage, utils: Utils, rugPullTracker: RugPullTracker) { this.lnd = lnd; this.settings = settings; @@ -68,7 +67,7 @@ export class Watchdog { await this.getTracker() const totalUsersBalance = await this.storage.paymentStorage.GetTotalUsersBalance() this.utils.stateBundler.AddBalancePoint('usersBalance', totalUsersBalance) - const { totalExternal } = await this.getAggregatedExternalBalance() + const { totalExternal, otherExternal } = await this.getAggregatedExternalBalance() this.initialLndBalance = totalExternal this.initialUsersBalance = totalUsersBalance const fwEvents = await this.lnd.GetForwardingHistory(0, this.startedAtUnix) @@ -77,6 +76,8 @@ export class Watchdog { const paymentFound = await this.storage.paymentStorage.GetMaxPaymentIndex() const knownMaxIndex = paymentFound.length > 0 ? Math.max(paymentFound[0].paymentIndex, 0) : 0 this.latestPaymentIndexOffset = await this.lnd.GetLatestPaymentIndex(knownMaxIndex) + const other = { ilnd: this.initialLndBalance, hf: this.accumulatedHtlcFees, iu: this.initialUsersBalance, tu: totalUsersBalance, oext: otherExternal } + //getLogger({ component: 'watchdog_debug2' })(JSON.stringify({ deltaLnd: 0, deltaUsers: 0, totalExternal, latestIndex: this.latestPaymentIndexOffset, other })) this.interval = setInterval(() => { if (this.latestCheckStart + (1000 * 58) < Date.now()) { this.PaymentRequested() @@ -92,49 +93,7 @@ export class Watchdog { fwEvents.forwardingEvents.forEach((event) => { this.accumulatedHtlcFees += Number(event.fee) }) - } - handleRootOperations = async () => { - let pendingChange = 0 - const pendingChainPayments = await this.storage.metricsStorage.GetPendingChainPayments() - for (const payment of pendingChainPayments) { - try { - const tx = await this.lnd.GetTx(payment.operation_identifier) - if (tx.numConfirmations > 0) { - await this.storage.metricsStorage.SetRootOpConfirmed(payment.serial_id) - continue - } - tx.outputDetails.forEach(o => pendingChange += o.isOurAddress ? Number(o.amount) : 0) - } catch (err: any) { - this.log("Error getting tx for root operation", err.message || err) - } - - } - let newReceived = 0 - let newSpent = 0 - if (this.lastHandlerRootOpsAtUnix === 0) { - this.lastHandlerRootOpsAtUnix = Math.floor(Date.now() / 1000) - return { newReceived, newSpent, pendingChange } - } - - const newOps = await this.storage.metricsStorage.GetRootOperations({ from: this.lastHandlerRootOpsAtUnix }) - newOps.forEach(o => { - switch (o.operation_type) { - case 'chain_payment': - newSpent += Number(o.operation_amount) - break - case 'invoice_payment': - newSpent += Number(o.operation_amount) - break - case 'chain': - newReceived += Number(o.operation_amount) - break - case 'invoice': - newReceived += Number(o.operation_amount) - break - } - }) - return { newReceived, newSpent, pendingChange } } getAggregatedExternalBalance = async () => { @@ -142,9 +101,8 @@ export class Watchdog { const feesPaidForLiquidity = this.liquidityManager.GetPaidFees() const pb = await this.rugPullTracker.CheckProviderBalance() const providerBalance = pb.prevBalance || pb.balance - const { newReceived, newSpent, pendingChange } = await this.handleRootOperations() - const opsTotal = newReceived + pendingChange - newSpent - return { totalExternal: totalLndBalance + providerBalance + feesPaidForLiquidity + opsTotal } + const otherExternal = { pb: providerBalance, f: feesPaidForLiquidity, lnd: totalLndBalance, olnd: othersFromLnd } + return { totalExternal: totalLndBalance + providerBalance + feesPaidForLiquidity, otherExternal } } checkBalanceUpdate = async (deltaLnd: number, deltaUsers: number) => { @@ -229,7 +187,7 @@ export class Watchdog { } const totalUsersBalance = await this.storage.paymentStorage.GetTotalUsersBalance() this.utils.stateBundler.AddBalancePoint('usersBalance', totalUsersBalance) - const { totalExternal } = await this.getAggregatedExternalBalance() + const { totalExternal, otherExternal } = await this.getAggregatedExternalBalance() this.utils.stateBundler.AddBalancePoint('accumulatedHtlcFees', this.accumulatedHtlcFees) const deltaLnd = totalExternal - (this.initialLndBalance + this.accumulatedHtlcFees) const deltaUsers = totalUsersBalance - this.initialUsersBalance @@ -238,6 +196,8 @@ export class Watchdog { const knownMaxIndex = Math.max(maxFromDb, this.latestPaymentIndexOffset) const newLatest = await this.lnd.GetLatestPaymentIndex(knownMaxIndex) const historyMismatch = newLatest > knownMaxIndex + const other = { ilnd: this.initialLndBalance, hf: this.accumulatedHtlcFees, iu: this.initialUsersBalance, tu: totalUsersBalance, km: knownMaxIndex, nl: newLatest, oext: otherExternal } + //getLogger({ component: 'watchdog_debug2' })(JSON.stringify({ deltaLnd, deltaUsers, totalExternal, other })) const deny = await this.checkBalanceUpdate(deltaLnd, deltaUsers) if (historyMismatch) { getLogger({ component: 'bark' })("History mismatch detected in absolute update, locking outgoing operations") diff --git a/src/services/metrics/index.ts b/src/services/metrics/index.ts index 9e23b665..3dbafedb 100644 --- a/src/services/metrics/index.ts +++ b/src/services/metrics/index.ts @@ -414,7 +414,9 @@ export default class Handler { await this.storage.metricsStorage.AddRootOperation("chain", `${address}:${txOutput.hash}:${txOutput.index}`, amount) } - + async GetRootAddressTransaction(address: string, txHash: string, index: number) { + return this.storage.metricsStorage.GetRootOperation("chain", `${address}:${txHash}:${index}`) + } async AddRootInvoicePaid(paymentRequest: string, amount: number) { await this.storage.metricsStorage.AddRootOperation("invoice", paymentRequest, amount) @@ -423,13 +425,8 @@ export default class Handler { const mapRootOpType = (opType: string): Types.OperationType => { switch (opType) { - case "chain_payment": - case "chain": - return Types.OperationType.CHAIN_OP - case "invoice_payment": - case "invoice": - return Types.OperationType.INVOICE_OP - + case "chain": return Types.OperationType.CHAIN_OP + case "invoice": return Types.OperationType.INVOICE_OP default: throw new Error("Unknown operation type") } } \ No newline at end of file diff --git a/src/services/nostr/index.ts b/src/services/nostr/index.ts index ffa636b6..3dce7b41 100644 --- a/src/services/nostr/index.ts +++ b/src/services/nostr/index.ts @@ -11,69 +11,28 @@ export default class NostrSubprocess { utils: Utils awaitingPongs: (() => void)[] = [] log = getLogger({}) - latestRestart = 0 - private settings: NostrSettings - private eventCallback: EventCallback - private beaconCallback: BeaconCallback - private isShuttingDown = false - constructor(settings: NostrSettings, utils: Utils, eventCallback: EventCallback, beaconCallback: BeaconCallback) { this.utils = utils - this.settings = settings - this.eventCallback = eventCallback - this.beaconCallback = beaconCallback - this.startSubProcess() - } - - private cleanupProcess() { - if (this.childProcess) { - this.childProcess.removeAllListeners() - if (!this.childProcess.killed) { - this.childProcess.kill('SIGTERM') - } - } - } - - private startSubProcess() { - this.cleanupProcess() - this.childProcess = fork("./build/src/services/nostr/handler") - this.childProcess.on("error", (error) => { this.log(ERROR, "nostr subprocess error", error) }) - this.childProcess.on("exit", (code, signal) => { - if (this.isShuttingDown) { - this.log("nostr subprocess stopped") + this.childProcess.on("exit", (code) => { + this.log(ERROR, `nostr subprocess exited with code ${code}`) + if (!code) { return } - - if (code === 0) { - this.log("nostr subprocess exited cleanly") - return - } - - this.log(ERROR, `nostr subprocess exited with code ${code} and signal ${signal}`) - - const now = Date.now() - if (now - this.latestRestart < 5000) { - this.log(ERROR, "nostr subprocess exited too quickly, not restarting") - throw new Error("nostr subprocess crashed repeatedly") - } - - this.log("restarting nostr subprocess...") - this.latestRestart = now - setTimeout(() => this.startSubProcess(), 100) + throw new Error(`nostr subprocess exited with code ${code}`) }) this.childProcess.on("message", (message: ChildProcessResponse) => { switch (message.type) { case 'ready': - this.sendToChildProcess({ type: 'settings', settings: this.settings }) + this.sendToChildProcess({ type: 'settings', settings: settings }) break; case 'event': - this.eventCallback(message.event) + eventCallback(message.event) break case 'processMetrics': this.utils.tlvStorageFactory.ProcessMetrics(message.metrics, 'nostr') @@ -83,7 +42,7 @@ export default class NostrSubprocess { this.awaitingPongs = [] break case 'beacon': - this.beaconCallback({ content: message.content, pub: message.pub }) + beaconCallback({ content: message.content, pub: message.pub }) break default: console.error("unknown nostr event response", message) @@ -91,15 +50,11 @@ export default class NostrSubprocess { } }) } - sendToChildProcess(message: ChildProcessRequest) { - if (this.childProcess && !this.childProcess.killed) { - this.childProcess.send(message) - } + this.childProcess.send(message) } Reset(settings: NostrSettings) { - this.settings = settings this.sendToChildProcess({ type: 'settings', settings }) } @@ -113,9 +68,7 @@ export default class NostrSubprocess { Send(initiator: SendInitiator, data: SendData, relays?: string[]) { this.sendToChildProcess({ type: 'send', data, initiator, relays }) } - Stop() { - this.isShuttingDown = true - this.cleanupProcess() + this.childProcess.kill() } } diff --git a/src/services/serverMethods/index.ts b/src/services/serverMethods/index.ts index d74e67fd..8b9b80a3 100644 --- a/src/services/serverMethods/index.ts +++ b/src/services/serverMethods/index.ts @@ -91,14 +91,6 @@ export default (mainHandler: Main): Types.ServerMethods => { if (err != null) throw new Error(err.message) return mainHandler.adminManager.CloseChannel(req) }, - BumpTx: async ({ ctx, req }) => { - const err = Types.BumpTxValidate(req, { - txid_CustomCheck: txid => txid !== '', - sat_per_vbyte_CustomCheck: spv => spv > 0 - }) - if (err != null) throw new Error(err.message) - return mainHandler.adminManager.BumpTx(req) - }, GetAdminTransactionSwapQuotes: async ({ ctx, req }) => { const err = Types.TransactionSwapRequestValidate(req, { transaction_amount_sats_CustomCheck: amt => amt > 0 @@ -114,36 +106,6 @@ export default (mainHandler: Main): Types.ServerMethods => { if (err != null) throw new Error(err.message) return mainHandler.adminManager.PayAdminTransactionSwap(req) }, - ListAdminTxSwaps: async ({ ctx }) => { - return mainHandler.adminManager.ListAdminTxSwaps() - }, - GetAdminInvoiceSwapQuotes: async ({ ctx, req }) => { - const err = Types.InvoiceSwapRequestValidate(req, { - amount_sats_CustomCheck: amt => amt > 0 - }) - if (err != null) throw new Error(err.message) - return mainHandler.adminManager.GetAdminInvoiceSwapQuotes(req) - }, - RefundAdminInvoiceSwap: async ({ ctx, req }) => { - const err = Types.RefundAdminInvoiceSwapRequestValidate(req, { - swap_operation_id_CustomCheck: id => id !== '', - }) - if (err != null) throw new Error(err.message) - return mainHandler.adminManager.RefundAdminInvoiceSwap(req) - }, - ListAdminInvoiceSwaps: async ({ ctx }) => { - return mainHandler.adminManager.ListAdminInvoiceSwaps() - }, - PayAdminInvoiceSwap: async ({ ctx, req }) => { - const err = Types.PayAdminInvoiceSwapRequestValidate(req, { - swap_operation_id_CustomCheck: id => id !== '', - }) - if (err != null) throw new Error(err.message) - return mainHandler.adminManager.PayAdminInvoiceSwap(req) - }, - GetAssetsAndLiabilities: async ({ ctx, req }) => { - return mainHandler.adminManager.GetAssetsAndLiabilities(req) - }, GetProvidersDisruption: async () => { return mainHandler.metricsManager.GetProvidersDisruption() }, @@ -183,7 +145,9 @@ export default (mainHandler: Main): Types.ServerMethods => { GetUserOperations: async ({ ctx, req }) => { return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req) }, - + ListAdminSwaps: async ({ ctx }) => { + return mainHandler.adminManager.ListAdminSwaps() + }, GetPaymentState: async ({ ctx, req }) => { const err = Types.GetPaymentStateRequestValidate(req, { invoice_CustomCheck: invoice => invoice !== "" @@ -195,14 +159,14 @@ export default (mainHandler: Main): Types.ServerMethods => { PayAddress: async ({ ctx, req }) => { const err = Types.PayAddressRequestValidate(req, { address_CustomCheck: addr => addr !== '', - // amountSats_CustomCheck: amt => amt > 0, + amountSats_CustomCheck: amt => amt > 0, // satsPerVByte_CustomCheck: spb => spb > 0 }) if (err != null) throw new Error(err.message) return mainHandler.paymentManager.PayAddress(ctx, req) }, - ListTxSwaps: async ({ ctx }) => { - return mainHandler.paymentManager.ListTxSwaps(ctx) + ListSwaps: async ({ ctx }) => { + return mainHandler.paymentManager.ListSwaps(ctx) }, GetTransactionSwapQuotes: async ({ ctx, req }) => { return mainHandler.paymentManager.GetTransactionSwapQuotes(ctx, req) diff --git a/src/services/storage/applicationStorage.ts b/src/services/storage/applicationStorage.ts index 402e7773..21f6f9c9 100644 --- a/src/services/storage/applicationStorage.ts +++ b/src/services/storage/applicationStorage.ts @@ -1,5 +1,5 @@ import crypto from 'crypto'; -import { Between, FindOperator, IsNull, LessThanOrEqual, MoreThanOrEqual } from "typeorm" +import { Between, FindOperator, IsNull, LessThanOrEqual, MoreThanOrEqual, In } from "typeorm" import { generateSecretKey, getPublicKey } from 'nostr-tools'; import { Application } from "./entity/Application.js" import UserStorage from './userStorage.js'; @@ -72,8 +72,7 @@ export default class { user: user, application, identifier: userIdentifier, - nostr_public_key: nostrPub, - topic_id: crypto.randomBytes(32).toString('hex') + nostr_public_key: nostrPub }, txId) }) } @@ -161,16 +160,10 @@ export default class { this.dbs.Remove('User', baseUser, txId) } - async RemoveAppUsersAndBaseUsers(appUserIds: string[], baseUser: string, txId?: string) { - for (const appUserId of appUserIds) { - const appUser = await this.dbs.FindOne('ApplicationUser', { where: { identifier: appUserId } }, txId) - if (appUser) { - await this.dbs.Delete('ApplicationUser', appUser.serial_id, txId) - } - } - const user = await this.userStorage.FindUser(baseUser, txId) - if (!user) return - await this.dbs.Delete('User', user.serial_id, txId) + async RemoveAppUsersAndBaseUsers(appUserIds: string[],baseUser:string, txId?: string) { + await this.dbs.Delete('ApplicationUser', { identifier: In(appUserIds) }, txId) + await this.dbs.Delete('User', { user_id: baseUser }, txId) + } diff --git a/src/services/storage/db/db.ts b/src/services/storage/db/db.ts index 63397c58..335f6848 100644 --- a/src/services/storage/db/db.ts +++ b/src/services/storage/db/db.ts @@ -30,7 +30,6 @@ import * as fs from 'fs' import { UserAccess } from "../entity/UserAccess.js" import { AdminSettings } from "../entity/AdminSettings.js" import { TransactionSwap } from "../entity/TransactionSwap.js" -import { InvoiceSwap } from "../entity/InvoiceSwap.js" export type DbSettings = { @@ -77,8 +76,7 @@ export const MainDbEntities = { 'AppUserDevice': AppUserDevice, 'UserAccess': UserAccess, 'AdminSettings': AdminSettings, - 'TransactionSwap': TransactionSwap, - 'InvoiceSwap': InvoiceSwap + 'TransactionSwap': TransactionSwap } export type MainDbNames = keyof typeof MainDbEntities export const MainDbEntitiesNames = Object.keys(MainDbEntities) diff --git a/src/services/storage/db/serializationHelpers.ts b/src/services/storage/db/serializationHelpers.ts index ee19201f..eb27f678 100644 --- a/src/services/storage/db/serializationHelpers.ts +++ b/src/services/storage/db/serializationHelpers.ts @@ -8,19 +8,10 @@ type SerializedFindOperator = { } export function serializeFindOperator(operator: FindOperator): SerializedFindOperator { - let value: any; - if (Array.isArray(operator['value']) && operator['type'] !== 'between') { - value = operator['value'].map(serializeFindOperator); - } else if ((operator as any).child !== undefined) { - // Not(IsNull()) etc.: TypeORM's .value getter unwraps nested FindOperators, so we'd lose the inner operator. Use .child to serialize the nested operator. - value = serializeFindOperator((operator as any).child); - } else { - value = operator['value']; - } return { _type: 'FindOperator', type: operator['type'], - value, + value: (Array.isArray(operator['value']) && operator['type'] !== 'between') ? operator["value"].map(serializeFindOperator) : operator["value"], }; } @@ -60,8 +51,7 @@ export function deserializeFindOperator(serialized: SerializedFindOperator): Fin } } -export function serializeRequest(r: object, debug = false): T { - if (debug) console.log("serializeRequest", r) +export function serializeRequest(r: object): T { if (!r || typeof r !== 'object') { return r; } @@ -71,24 +61,23 @@ export function serializeRequest(r: object, debug = false): T { } if (Array.isArray(r)) { - return r.map(item => serializeRequest(item, debug)) as any; + return r.map(item => serializeRequest(item)) as any; } const result: any = {}; for (const [key, value] of Object.entries(r)) { - result[key] = serializeRequest(value, debug); + result[key] = serializeRequest(value); } return result; } -export function deserializeRequest(r: object, debug = false): T { - if (debug) console.log("deserializeRequest", r) +export function deserializeRequest(r: object): T { if (!r || typeof r !== 'object') { return r; } if (Array.isArray(r)) { - return r.map(item => deserializeRequest(item, debug)) as any; + return r.map(item => deserializeRequest(item)) as any; } if (r && typeof r === 'object' && (r as any)._type === 'FindOperator') { @@ -97,7 +86,7 @@ export function deserializeRequest(r: object, debug = false): T { const result: any = {}; for (const [key, value] of Object.entries(r)) { - result[key] = deserializeRequest(value, debug); + result[key] = deserializeRequest(value); } return result; } diff --git a/src/services/storage/db/storageInterface.ts b/src/services/storage/db/storageInterface.ts index 976ec20d..941d9533 100644 --- a/src/services/storage/db/storageInterface.ts +++ b/src/services/storage/db/storageInterface.ts @@ -29,7 +29,7 @@ export class StorageInterface extends EventEmitter { private debug: boolean = false; private utils: Utils private dbType: 'main' | 'metrics' - private log = getLogger({ component: 'StorageInterface' }) + private log = getLogger({component: 'StorageInterface'}) constructor(utils: Utils) { super(); this.initializeSubprocess(); @@ -61,13 +61,13 @@ export class StorageInterface extends EventEmitter { this.isConnected = false; }); - this.process.on('exit', (code: number, signal: string) => { - this.log(ERROR, `Storage processor exited with code ${code} and signal ${signal}`); + this.process.on('exit', (code: number) => { + this.log(ERROR, `Storage processor exited with code ${code}`); this.isConnected = false; - if (code === 0) { + if (!code) { return } - throw new Error(`Storage processor exited with code ${code} and signal ${signal}`) + throw new Error(`Storage processor exited with code ${code}`) }); this.isConnected = true; @@ -104,10 +104,9 @@ export class StorageInterface extends EventEmitter { return this.handleOp(findOp) } - Find(entity: DBNames, q: QueryOptions, txId?: string, debug = false): Promise { - if (debug) console.log("Find", { entity }) + Find(entity: DBNames, q: QueryOptions, txId?: string): Promise { const opId = Math.random().toString() - const findOp: FindOperation = { type: 'find', entity, opId, q, txId, debug } + const findOp: FindOperation = { type: 'find', entity, opId, q, txId } return this.handleOp(findOp) } @@ -167,33 +166,32 @@ export class StorageInterface extends EventEmitter { } private handleOp(op: IStorageOperation): Promise { - if (this.debug || op.debug) console.log('handleOp', op) + if (this.debug) console.log('handleOp', op) this.checkConnected() return new Promise((resolve, reject) => { const responseHandler = (response: OperationResponse) => { - if (this.debug || op.debug) console.log('responseHandler', response) + if (this.debug) console.log('responseHandler', response) if (!response.success) { reject(new Error(response.error)); return } - if (this.debug || op.debug) console.log("response", response, op) if (response.type !== op.type) { reject(new Error('Invalid storage response type')); return } - resolve(deserializeResponseData(response.data)); + resolve(deserializeResponseData(response.data)); } this.once(op.opId, responseHandler) this.process.send(this.serializeOperation(op)) }) } - private serializeOperation(operation: IStorageOperation, debug = false): IStorageOperation { + private serializeOperation(operation: IStorageOperation): IStorageOperation { const serialized = { ...operation }; if ('q' in serialized) { - (serialized as any).q = serializeRequest((serialized as any).q, debug); + (serialized as any).q = serializeRequest((serialized as any).q); } - if (this.debug || debug) { + if (this.debug) { serialized.debug = true } return serialized; @@ -207,7 +205,7 @@ export class StorageInterface extends EventEmitter { public disconnect() { if (this.process) { - this.process.kill(0); + this.process.kill(); this.isConnected = false; this.debug = false; } diff --git a/src/services/storage/entity/ApplicationUser.ts b/src/services/storage/entity/ApplicationUser.ts index c4717721..2284b9bd 100644 --- a/src/services/storage/entity/ApplicationUser.ts +++ b/src/services/storage/entity/ApplicationUser.ts @@ -26,9 +26,6 @@ export class ApplicationUser { @Column({ default: "" }) callback_url: string - @Column({ unique: true }) - topic_id: string; - @CreateDateColumn() created_at: Date diff --git a/src/services/storage/entity/InvoiceSwap.ts b/src/services/storage/entity/InvoiceSwap.ts deleted file mode 100644 index 746756b8..00000000 --- a/src/services/storage/entity/InvoiceSwap.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne, JoinColumn, UpdateDateColumn } from "typeorm"; -import { User } from "./User"; - -@Entity() -export class InvoiceSwap { - @PrimaryGeneratedColumn('uuid') - swap_operation_id: string - - @Column() - app_user_id: string - - @Column() - swap_quote_id: string - - @Column() - swap_tree: string - - @Column() - claim_public_key: string - - @Column() - payment_hash: string - - /* @Column() - lockup_address: string */ - - /* @Column() - refund_public_key: string */ - - @Column() - timeout_block_height: number - - @Column() - invoice: string - - @Column() - invoice_amount: number - - @Column() - transaction_amount: number - - @Column() - swap_fee_sats: number - - @Column() - chain_fee_sats: number - - - - @Column() - ephemeral_public_key: string - - @Column() - address: string - - // the private key is used on to perform a swap, it does not hold any funds once the swap is completed - // the swap should only last a few seconds, so it is not a security risk to store the private key in the database - // the key is stored here mostly for recovery purposes, in case something goes wrong with the swap - @Column() - ephemeral_private_key: string - - @Column({ default: false }) - used: boolean - - @Column({ default: 0 }) - completed_at_unix: number - - @Column({ default: 0 }) - paid_at_unix: number - - @Column({ default: "" }) - preimage: string - - @Column({ default: "" }) - failure_reason: string - - @Column({ default: "" }) - tx_id: string - - @Column({ default: "", type: "text" }) - lockup_tx_hex: string - - /* @Column({ default: "" }) - address_paid: string */ - - @Column({ default: "" }) - service_url: string - - @CreateDateColumn() - created_at: Date - - @UpdateDateColumn() - updated_at: Date -} \ No newline at end of file diff --git a/src/services/storage/entity/RootOperation.ts b/src/services/storage/entity/RootOperation.ts index ec4914bc..3a2bd1f9 100644 --- a/src/services/storage/entity/RootOperation.ts +++ b/src/services/storage/entity/RootOperation.ts @@ -17,9 +17,6 @@ export class RootOperation { @Column({ default: 0 }) at_unix: number - @Column({ default: false }) - pending: boolean - @CreateDateColumn() created_at: Date diff --git a/src/services/storage/entity/TransactionSwap.ts b/src/services/storage/entity/TransactionSwap.ts index d2a99f52..7403e2a1 100644 --- a/src/services/storage/entity/TransactionSwap.ts +++ b/src/services/storage/entity/TransactionSwap.ts @@ -60,12 +60,6 @@ export class TransactionSwap { @Column({ default: "" }) tx_id: string - @Column({ default: 0 }) - completed_at_unix: number - - @Column({ default: 0 }) - paid_at_unix: number - @Column({ default: "" }) address_paid: string diff --git a/src/services/storage/metricsStorage.ts b/src/services/storage/metricsStorage.ts index d80d11c9..44da304c 100644 --- a/src/services/storage/metricsStorage.ts +++ b/src/services/storage/metricsStorage.ts @@ -10,7 +10,6 @@ import { StorageInterface } from "./db/storageInterface.js"; import { Utils } from "../helpers/utilsWrapper.js"; import { Channel, ChannelEventUpdate } from "../../../proto/lnd/lightning.js"; import { ChannelEvent } from "./entity/ChannelEvent.js"; -export type RootOperationType = 'chain' | 'invoice' | 'chain_payment' | 'invoice_payment' export default class { //DB: DataSource | EntityManager settings: StorageSettings @@ -146,27 +145,13 @@ export default class { } } - async AddRootOperation(opType: RootOperationType, id: string, amount: number, pending = false, dbTxId?: string) { - return this.dbs.CreateAndSave('RootOperation', { - operation_type: opType, operation_amount: amount, - operation_identifier: id, at_unix: Math.floor(Date.now() / 1000), pending - }, dbTxId) + async AddRootOperation(opType: string, id: string, amount: number, txId?: string) { + return this.dbs.CreateAndSave('RootOperation', { operation_type: opType, operation_amount: amount, operation_identifier: id, at_unix: Math.floor(Date.now() / 1000) }, txId) } - async GetRootOperation(opType: RootOperationType, id: string, txId?: string) { + async GetRootOperation(opType: string, id: string, txId?: string) { return this.dbs.FindOne('RootOperation', { where: { operation_type: opType, operation_identifier: id } }, txId) } - async GetRootAddressTransaction(address: string, txHash: string, index: number) { - return this.GetRootOperation("chain", `${address}:${txHash}:${index}`) - } - - async GetPendingChainPayments() { - return this.dbs.Find('RootOperation', { where: { operation_type: 'chain_payment', pending: true } }) - } - - async SetRootOpConfirmed(serialId: number) { - return this.dbs.Update('RootOperation', serialId, { pending: false }) - } async GetRootOperations({ from, to }: { from?: number, to?: number }, txId?: string) { const q = getTimeQuery({ from, to }) diff --git a/src/services/storage/migrations/1769529793283-invoice_swaps.ts b/src/services/storage/migrations/1769529793283-invoice_swaps.ts deleted file mode 100644 index f7b93755..00000000 --- a/src/services/storage/migrations/1769529793283-invoice_swaps.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class InvoiceSwaps1769529793283 implements MigrationInterface { - name = 'InvoiceSwaps1769529793283' - - public async up(queryRunner: QueryRunner): Promise { - 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')))`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "invoice_swap"`); - } - -} diff --git a/src/services/storage/migrations/1769805357459-invoice_swaps_fixes.ts b/src/services/storage/migrations/1769805357459-invoice_swaps_fixes.ts deleted file mode 100644 index 3ba13031..00000000 --- a/src/services/storage/migrations/1769805357459-invoice_swaps_fixes.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class InvoiceSwapsFixes1769805357459 implements MigrationInterface { - name = 'InvoiceSwapsFixes1769805357459' - - public async up(queryRunner: QueryRunner): Promise { - 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 (''))`); - 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") 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" 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 { - 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')))`); - 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") 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" FROM "temporary_invoice_swap"`); - await queryRunner.query(`DROP TABLE "temporary_invoice_swap"`); - } - -} diff --git a/src/services/storage/migrations/1770038768784-application_user_topic_id.ts b/src/services/storage/migrations/1770038768784-application_user_topic_id.ts deleted file mode 100644 index b520cbe9..00000000 --- a/src/services/storage/migrations/1770038768784-application_user_topic_id.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class ApplicationUserTopicId1770038768784 implements MigrationInterface { - name = 'ApplicationUserTopicId1770038768784' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`); - await queryRunner.query(`CREATE TABLE "temporary_application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, "callback_url" varchar NOT NULL DEFAULT (''), "topic_id" varchar NOT NULL, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"), CONSTRAINT "UQ_bd1a42f39fd7b4218bed5cc63d9" UNIQUE ("topic_id"), CONSTRAINT "FK_0796a381bcc624f52e9a155712b" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1b3bdb6f660cd99533a1e673ef1" FOREIGN KEY ("applicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); - await queryRunner.query(`INSERT INTO "temporary_application_user"("serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId", "callback_url", "topic_id") SELECT "serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId", "callback_url", lower(hex(randomblob(32))) FROM "application_user"`); - await queryRunner.query(`DROP TABLE "application_user"`); - await queryRunner.query(`ALTER TABLE "temporary_application_user" RENAME TO "application_user"`); - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`); - await queryRunner.query(`ALTER TABLE "application_user" RENAME TO "temporary_application_user"`); - await queryRunner.query(`CREATE TABLE "application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, "callback_url" varchar NOT NULL DEFAULT (''), CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"), CONSTRAINT "FK_0796a381bcc624f52e9a155712b" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1b3bdb6f660cd99533a1e673ef1" FOREIGN KEY ("applicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); - await queryRunner.query(`INSERT INTO "application_user"("serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId", "callback_url") SELECT "serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId", "callback_url" FROM "temporary_application_user"`); - await queryRunner.query(`DROP TABLE "temporary_application_user"`); - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `); - } - -} diff --git a/src/services/storage/migrations/1771347307798-swap_timestamps.ts b/src/services/storage/migrations/1771347307798-swap_timestamps.ts deleted file mode 100644 index ce5c0b39..00000000 --- a/src/services/storage/migrations/1771347307798-swap_timestamps.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class SwapTimestamps1771347307798 implements MigrationInterface { - name = 'SwapTimestamps1771347307798' - - public async up(queryRunner: QueryRunner): Promise { - 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 { - 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"`); - } - -} diff --git a/src/services/storage/migrations/1771524665409-root_op_pending.ts b/src/services/storage/migrations/1771524665409-root_op_pending.ts deleted file mode 100644 index e65461f3..00000000 --- a/src/services/storage/migrations/1771524665409-root_op_pending.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class RootOpPending1771524665409 implements MigrationInterface { - name = 'RootOpPending1771524665409' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "temporary_root_operation" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "operation_type" varchar NOT NULL, "operation_amount" integer NOT NULL, "operation_identifier" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "at_unix" integer NOT NULL DEFAULT (0), "pending" boolean NOT NULL DEFAULT (0))`); - await queryRunner.query(`INSERT INTO "temporary_root_operation"("serial_id", "operation_type", "operation_amount", "operation_identifier", "created_at", "updated_at", "at_unix") SELECT "serial_id", "operation_type", "operation_amount", "operation_identifier", "created_at", "updated_at", "at_unix" FROM "root_operation"`); - await queryRunner.query(`DROP TABLE "root_operation"`); - await queryRunner.query(`ALTER TABLE "temporary_root_operation" RENAME TO "root_operation"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "root_operation" RENAME TO "temporary_root_operation"`); - await queryRunner.query(`CREATE TABLE "root_operation" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "operation_type" varchar NOT NULL, "operation_amount" integer NOT NULL, "operation_identifier" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "at_unix" integer NOT NULL DEFAULT (0))`); - await queryRunner.query(`INSERT INTO "root_operation"("serial_id", "operation_type", "operation_amount", "operation_identifier", "created_at", "updated_at", "at_unix") SELECT "serial_id", "operation_type", "operation_amount", "operation_identifier", "created_at", "updated_at", "at_unix" FROM "temporary_root_operation"`); - await queryRunner.query(`DROP TABLE "temporary_root_operation"`); - } - -} diff --git a/src/services/storage/migrations/1771878683383-tx_swap_timestamps.ts b/src/services/storage/migrations/1771878683383-tx_swap_timestamps.ts deleted file mode 100644 index be9ccade..00000000 --- a/src/services/storage/migrations/1771878683383-tx_swap_timestamps.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class TxSwapTimestamps1771878683383 implements MigrationInterface { - name = 'TxSwapTimestamps1771878683383' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "temporary_transaction_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, "lockup_address" varchar NOT NULL, "refund_public_key" 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, "preimage" varchar NOT NULL, "ephemeral_public_key" varchar NOT NULL, "ephemeral_private_key" varchar NOT NULL, "used" boolean NOT NULL DEFAULT (0), "failure_reason" varchar NOT NULL DEFAULT (''), "tx_id" varchar NOT NULL DEFAULT (''), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "address_paid" varchar NOT NULL DEFAULT (''), "service_url" varchar 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_transaction_swap"("swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "lockup_address", "refund_public_key", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "preimage", "ephemeral_public_key", "ephemeral_private_key", "used", "failure_reason", "tx_id", "created_at", "updated_at", "address_paid", "service_url") SELECT "swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "lockup_address", "refund_public_key", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "preimage", "ephemeral_public_key", "ephemeral_private_key", "used", "failure_reason", "tx_id", "created_at", "updated_at", "address_paid", "service_url" FROM "transaction_swap"`); - await queryRunner.query(`DROP TABLE "transaction_swap"`); - await queryRunner.query(`ALTER TABLE "temporary_transaction_swap" RENAME TO "transaction_swap"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "transaction_swap" RENAME TO "temporary_transaction_swap"`); - await queryRunner.query(`CREATE TABLE "transaction_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, "lockup_address" varchar NOT NULL, "refund_public_key" 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, "preimage" varchar NOT NULL, "ephemeral_public_key" varchar NOT NULL, "ephemeral_private_key" varchar NOT NULL, "used" boolean NOT NULL DEFAULT (0), "failure_reason" varchar NOT NULL DEFAULT (''), "tx_id" varchar NOT NULL DEFAULT (''), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "address_paid" varchar NOT NULL DEFAULT (''), "service_url" varchar NOT NULL DEFAULT (''))`); - await queryRunner.query(`INSERT INTO "transaction_swap"("swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "lockup_address", "refund_public_key", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "preimage", "ephemeral_public_key", "ephemeral_private_key", "used", "failure_reason", "tx_id", "created_at", "updated_at", "address_paid", "service_url") SELECT "swap_operation_id", "app_user_id", "swap_quote_id", "swap_tree", "lockup_address", "refund_public_key", "timeout_block_height", "invoice", "invoice_amount", "transaction_amount", "swap_fee_sats", "chain_fee_sats", "preimage", "ephemeral_public_key", "ephemeral_private_key", "used", "failure_reason", "tx_id", "created_at", "updated_at", "address_paid", "service_url" FROM "temporary_transaction_swap"`); - await queryRunner.query(`DROP TABLE "temporary_transaction_swap"`); - } - -} diff --git a/src/services/storage/migrations/runner.ts b/src/services/storage/migrations/runner.ts index c78af2eb..d14b8381 100644 --- a/src/services/storage/migrations/runner.ts +++ b/src/services/storage/migrations/runner.ts @@ -1,21 +1,28 @@ import { Initial1703170309875 } from './1703170309875-initial.js' +import { LndMetrics1703170330183 } from './1703170330183-lnd_metrics.js' +import { ChannelRouting1709316653538 } from './1709316653538-channel_routing.js' import { LspOrder1718387847693 } from './1718387847693-lsp_order.js' import { LiquidityProvider1719335699480 } from './1719335699480-liquidity_provider.js' import { LndNodeInfo1720187506189 } from './1720187506189-lnd_node_info.js' import { TrackedProvider1720814323679 } from './1720814323679-tracked_provider.js' import { CreateInviteTokenTable1721751414878 } from "./1721751414878-create_invite_token_table.js" import { PaymentIndex1721760297610 } from './1721760297610-payment_index.js' +import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js' +import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js' import { DebitAccess1726496225078 } from './1726496225078-debit_access.js' import { DebitAccessFixes1726685229264 } from './1726685229264-debit_access_fixes.js' import { DebitToPub1727105758354 } from './1727105758354-debit_to_pub.js' import { UserCbUrl1727112281043 } from './1727112281043-user_cb_url.js' +import { RootOps1732566440447 } from './1732566440447-root_ops.js' import { UserOffer1733502626042 } from './1733502626042-user_offer.js' +import { RootOpsTime1745428134124 } from './1745428134124-root_ops_time.js' +import { ChannelEvents1750777346411 } from './1750777346411-channel_events.js' import { ManagementGrant1751307732346 } from './1751307732346-management_grant.js' import { ManagementGrantBanned1751989251513 } from './1751989251513-management_grant_banned.js' import { InvoiceCallbackUrls1752425992291 } from './1752425992291-invoice_callback_urls.js' +import { AppUserDevice1753285173175 } from './1753285173175-app_user_device.js' import { OldSomethingLeftover1753106599604 } from './1753106599604-old_something_leftover.js' import { UserReceivingInvoiceIdx1753109184611 } from './1753109184611-user_receiving_invoice_idx.js' -import { AppUserDevice1753285173175 } from './1753285173175-app_user_device.js' import { UserAccess1759426050669 } from './1759426050669-user_access.js' import { AddBlindToUserOffer1760000000000 } from './1760000000000-add_blind_to_user_offer.js' import { ApplicationAvatarUrl1761000001000 } from './1761000001000-application_avatar_url.js' @@ -25,23 +32,6 @@ import { TxSwapAddress1764779178945 } from './1764779178945-tx_swap_address.js' import { ClinkRequester1765497600000 } from './1765497600000-clink_requester.js' import { TrackedProviderHeight1766504040000 } from './1766504040000-tracked_provider_height.js' import { SwapsServiceUrl1768413055036 } from './1768413055036-swaps_service_url.js' -import { InvoiceSwaps1769529793283 } from './1769529793283-invoice_swaps.js' -import { InvoiceSwapsFixes1769805357459 } from './1769805357459-invoice_swaps_fixes.js' -import { ApplicationUserTopicId1770038768784 } from './1770038768784-application_user_topic_id.js' -import { SwapTimestamps1771347307798 } from './1771347307798-swap_timestamps.js' -import { TxSwapTimestamps1771878683383 } from './1771878683383-tx_swap_timestamps.js' - -import { LndMetrics1703170330183 } from './1703170330183-lnd_metrics.js' -import { ChannelRouting1709316653538 } from './1709316653538-channel_routing.js' -import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js' -import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js' -import { RootOps1732566440447 } from './1732566440447-root_ops.js' -import { RootOpsTime1745428134124 } from './1745428134124-root_ops_time.js' -import { ChannelEvents1750777346411 } from './1750777346411-channel_events.js' - -import { RootOpPending1771524665409 } from './1771524665409-root_op_pending.js' - - export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, @@ -49,13 +39,9 @@ export const allMigrations = [Initial1703170309875, LspOrder1718387847693, Liqui DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513, InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000, AdminSettings1761683639419, TxSwap1762890527098, - TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036, - InvoiceSwaps1769529793283, InvoiceSwapsFixes1769805357459, ApplicationUserTopicId1770038768784, SwapTimestamps1771347307798, - TxSwapTimestamps1771878683383] + TxSwapAddress1764779178945, ClinkRequester1765497600000, TrackedProviderHeight1766504040000, SwapsServiceUrl1768413055036] - -export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, - RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411, RootOpPending1771524665409] +export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411] /* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise => { await connectAndMigrate(log, storageManager, allMigrations, allMetricsMigrations) return false diff --git a/src/services/storage/paymentStorage.ts b/src/services/storage/paymentStorage.ts index af96b6c5..ed3f84dd 100644 --- a/src/services/storage/paymentStorage.ts +++ b/src/services/storage/paymentStorage.ts @@ -15,7 +15,6 @@ import TransactionsQueue from "./db/transactionsQueue.js"; import { LoggedEvent } from './eventsLog.js'; import { StorageInterface } from './db/storageInterface.js'; import { TransactionSwap } from './entity/TransactionSwap.js'; -import { InvoiceSwap } from './entity/InvoiceSwap.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, clinkRequesterPub?: string, clinkRequesterEventId?: string } export const defaultInvoiceExpiry = 60 * 60 export default class { @@ -138,15 +137,7 @@ export default class { } async RemoveUserInvoices(userId: string, txId?: string) { - const invoices = await this.dbs.Find('UserReceivingInvoice', { where: { user: { user_id: userId } } }, txId) - if (invoices.length === 0) { - return 0 - } - let deleted = 0 - for (const invoice of invoices) { - deleted += await this.dbs.Delete('UserReceivingInvoice', invoice.serial_id, txId) - } - return deleted + return this.dbs.Delete('UserReceivingInvoice', { user: { user_id: userId } }, txId) } async GetAddressOwner(address: string, txId?: string): Promise { @@ -160,10 +151,6 @@ export default class { return this.dbs.FindOne('UserTransactionPayment', { where: { address, tx_hash: txHash } }, txId) } - async GetTxHashPaymentOwner(txHash: string, txId?: string): Promise { - return this.dbs.FindOne('UserTransactionPayment', { where: { tx_hash: txHash } }, txId) - } - async GetInvoiceOwner(paymentRequest: string, txId?: string): Promise { return this.dbs.FindOne('UserReceivingInvoice', { where: { invoice: paymentRequest } }, txId) } @@ -330,51 +317,7 @@ export default class { } async RemoveUserEphemeralKeys(userId: string, txId?: string) { - const keys = await this.dbs.Find('UserEphemeralKey', { where: { user: { user_id: userId } } }, txId) - if (keys.length === 0) { - return 0 - } - let deleted = 0 - for (const key of keys) { - deleted += await this.dbs.Delete('UserEphemeralKey', key.serial_id, txId) - } - return deleted - } - - async RemoveUserReceivingAddresses(userId: string, txId?: string) { - const addresses = await this.dbs.Find('UserReceivingAddress', { where: { user: { user_id: userId } } }, txId) - for (const addr of addresses) { - const txs = await this.dbs.Find('AddressReceivingTransaction', { where: { user_address: { serial_id: addr.serial_id } } }, txId) - for (const tx of txs) { - await this.dbs.Delete('AddressReceivingTransaction', tx.serial_id, txId) - } - await this.dbs.Delete('UserReceivingAddress', addr.serial_id, txId) - } - } - - async RemoveUserInvoicePayments(userId: string, txId?: string) { - const payments = await this.dbs.Find('UserInvoicePayment', { where: { user: { user_id: userId } } }, txId) - for (const p of payments) { - await this.dbs.Delete('UserInvoicePayment', p.serial_id, txId) - } - } - - async RemoveUserTransactionPayments(userId: string, txId?: string) { - const payments = await this.dbs.Find('UserTransactionPayment', { where: { user: { user_id: userId } } }, txId) - for (const p of payments) { - await this.dbs.Delete('UserTransactionPayment', p.serial_id, txId) - } - } - - async RemoveUserToUserPayments(userId: string, txId?: string) { - const asSender = await this.dbs.Find('UserToUserPayment', { where: { from_user: { user_id: userId } } }, txId) - const asReceiver = await this.dbs.Find('UserToUserPayment', { where: { to_user: { user_id: userId } } }, txId) - const seen = new Set() - for (const p of [...asSender, ...asReceiver]) { - if (seen.has(p.serial_id)) continue - seen.add(p.serial_id) - await this.dbs.Delete('UserToUserPayment', p.serial_id, txId) - } + return this.dbs.Delete('UserEphemeralKey', { user: { user_id: userId } }, txId) } async AddPendingUserToUserPayment(fromUserId: string, toUserId: string, amount: number, fee: number, linkedApplication: Application, txId: string) { @@ -504,12 +447,8 @@ export default class { } } - async GetTotalUsersBalance(excludeLocked?: boolean, txId?: string) { - const where: { locked?: boolean } = {} - if (excludeLocked) { - where.locked = false - } - const total = await this.dbs.Sum('User', "balance_sats", where, txId) + async GetTotalUsersBalance(txId?: string) { + const total = await this.dbs.Sum('User', "balance_sats", {}) return total || 0 } @@ -533,31 +472,20 @@ export default class { return this.dbs.FindOne('TransactionSwap', { where: { swap_operation_id: swapOperationId, used: false, app_user_id: appUserId } }, txId) } - async SetTransactionSwapPaid(swapOperationId: string, txId?: string) { - const now = Math.floor(Date.now() / 1000) - return this.dbs.Update('TransactionSwap', { swap_operation_id: swapOperationId }, { - paid_at_unix: now, - }, txId) - } - - async FinalizeTransactionSwap(swapOperationId: string, address: string, chainTxId: string, txId?: string) { - const now = Math.floor(Date.now() / 1000) + async FinalizeTransactionSwap(swapOperationId: string, address: string, txId: string) { return this.dbs.Update('TransactionSwap', { swap_operation_id: swapOperationId }, { used: true, - tx_id: chainTxId, + tx_id: txId, address_paid: address, - completed_at_unix: now, - }, txId) + }) } - async FailTransactionSwap(swapOperationId: string, address: string, failureReason: string, txId?: string) { - const now = Math.floor(Date.now() / 1000) + async FailTransactionSwap(swapOperationId: string, address: string, failureReason: string) { return this.dbs.Update('TransactionSwap', { swap_operation_id: swapOperationId }, { used: true, failure_reason: failureReason, address_paid: address, - completed_at_unix: now, - }, txId) + }) } async DeleteTransactionSwap(swapOperationId: string, txId?: string) { @@ -565,18 +493,18 @@ export default class { } async DeleteExpiredTransactionSwaps(currentHeight: number, txId?: string) { - return this.dbs.Delete('TransactionSwap', { timeout_block_height: LessThan(currentHeight), used: false }, txId) + return this.dbs.Delete('TransactionSwap', { timeout_block_height: LessThan(currentHeight) }, txId) } async ListPendingTransactionSwaps(appUserId: string, txId?: string) { return this.dbs.Find('TransactionSwap', { where: { used: false, app_user_id: appUserId } }, txId) } - async ListTxSwapPayments(userId: string, txId?: string) { + async ListSwapPayments(userId: string, txId?: string) { return this.dbs.Find('UserInvoicePayment', { where: { swap_operation_id: Not(IsNull()), user: { user_id: userId } } }, txId) } - async ListCompletedTxSwaps(appUserId: string, payments: UserInvoicePayment[], txId?: string) { + async ListCompletedSwaps(appUserId: string, payments: UserInvoicePayment[], txId?: string) { const completed = await this.dbs.Find('TransactionSwap', { where: { used: true, app_user_id: appUserId } }, txId) // const payments = await this.dbs.Find('UserInvoicePayment', { where: { swap_operation_id: Not(IsNull()), } }, txId) const paymentsMap = new Map() @@ -587,85 +515,6 @@ export default class { swap: c, payment: paymentsMap.get(c.swap_operation_id) })) } - - async AddInvoiceSwap(swap: Partial) { - return this.dbs.CreateAndSave('InvoiceSwap', swap) - } - - async GetInvoiceSwap(swapOperationId: string, appUserId: string, txId?: string) { - const swap = await this.dbs.FindOne('InvoiceSwap', { where: { swap_operation_id: swapOperationId, used: false, app_user_id: appUserId } }, txId) - if (!swap || swap.tx_id) { - return null - } - return swap - } - - async FinalizeInvoiceSwap(swapOperationId: string, txId?: string) { - const now = Math.floor(Date.now() / 1000) - return this.dbs.Update('InvoiceSwap', { swap_operation_id: swapOperationId }, { - used: true, - completed_at_unix: now, - }, txId) - } - - async UpdateInvoiceSwap(swapOperationId: string, update: Partial, txId?: string) { - return this.dbs.Update('InvoiceSwap', { swap_operation_id: swapOperationId }, update, txId) - } - - async SetInvoiceSwapTxId(swapOperationId: string, chainTxId: string, chainFeeSats: number, lockupTxHex?: string, txId?: string) { - const now = Math.floor(Date.now() / 1000) - const update: Partial = { - tx_id: chainTxId, - paid_at_unix: now, - chain_fee_sats: chainFeeSats, - } - if (lockupTxHex) { - update.lockup_tx_hex = lockupTxHex - } - return this.dbs.Update('InvoiceSwap', { swap_operation_id: swapOperationId }, update, txId) - } - - async FailInvoiceSwap(swapOperationId: string, failureReason: string, txId?: string) { - const now = Math.floor(Date.now() / 1000) - return this.dbs.Update('InvoiceSwap', { swap_operation_id: swapOperationId }, { - used: true, - failure_reason: failureReason, - completed_at_unix: now, - }, txId) - } - - async DeleteInvoiceSwap(swapOperationId: string, txId?: string) { - return this.dbs.Delete('InvoiceSwap', { swap_operation_id: swapOperationId }, txId) - } - - async DeleteExpiredInvoiceSwaps(currentHeight: number, txId?: string) { - return this.dbs.Delete('InvoiceSwap', { timeout_block_height: LessThan(currentHeight), used: false, tx_id: "" }, txId) - } - - async ListCompletedInvoiceSwaps(appUserId: string, txId?: string) { - return this.dbs.Find('InvoiceSwap', { where: { used: true, app_user_id: appUserId } }, txId) - } - - async ListPendingInvoiceSwaps(appUserId: string, txId?: string) { - return this.dbs.Find('InvoiceSwap', { where: { used: false, app_user_id: appUserId } }, txId) - } - - async ListUnfinishedInvoiceSwaps(txId?: string) { - const swaps = await this.dbs.Find('InvoiceSwap', { where: { used: false } }, txId) - return swaps.filter(s => !!s.tx_id) - } - - async GetRefundableInvoiceSwap(swapOperationId: string, txId?: string) { - const swap = await this.dbs.FindOne('InvoiceSwap', { where: { swap_operation_id: swapOperationId } }, txId) - if (!swap || !swap.tx_id) { - return null - } - if (swap.used && !swap.failure_reason) { - return null - } - return swap - } - } const orFail = async (resultPromise: Promise) => { diff --git a/src/services/storage/productStorage.ts b/src/services/storage/productStorage.ts index 75f3da0d..e6f2f662 100644 --- a/src/services/storage/productStorage.ts +++ b/src/services/storage/productStorage.ts @@ -21,14 +21,6 @@ export default class { } async RemoveUserProducts(userId: string, txId?: string) { - const products = await this.dbs.Find('Product', { where: { owner: { user_id: userId } } }, txId) - if (products.length === 0) { - return 0 - } - let deleted = 0 - for (const product of products) { - deleted += await this.dbs.Delete('Product', { product_id: product.product_id }, txId) - } - return deleted + return this.dbs.Delete('Product', { owner: { user_id: userId } }, txId) } } \ No newline at end of file diff --git a/src/services/storage/tlv/tlvFilesStorageFactory.ts b/src/services/storage/tlv/tlvFilesStorageFactory.ts index 3eb2d117..0e396703 100644 --- a/src/services/storage/tlv/tlvFilesStorageFactory.ts +++ b/src/services/storage/tlv/tlvFilesStorageFactory.ts @@ -53,13 +53,13 @@ export class TlvStorageFactory extends EventEmitter { this.isConnected = false; }); - this.process.on('exit', (code: number, signal: string) => { - this.log(ERROR, `Tlv Storage processor exited with code ${code} and signal ${signal}`); + this.process.on('exit', (code: number) => { + this.log(ERROR, `Tlv Storage processor exited with code ${code}`); this.isConnected = false; - if (code === 0) { + if (!code) { return } - throw new Error(`Tlv Storage processor exited with code ${code} and signal ${signal}`) + throw new Error(`Tlv Storage processor exited with code ${code}`) }); this.isConnected = true; @@ -173,7 +173,7 @@ export class TlvStorageFactory extends EventEmitter { public disconnect() { if (this.process) { - this.process.kill(0); + this.process.kill(); this.isConnected = false; this.debug = false; } diff --git a/src/services/storage/userStorage.ts b/src/services/storage/userStorage.ts index a1541bac..58dd6cf5 100644 --- a/src/services/storage/userStorage.ts +++ b/src/services/storage/userStorage.ts @@ -42,7 +42,7 @@ export default class { async GetUser(userId: string, txId?: string): Promise { const user = await this.FindUser(userId, txId) if (!user) { - throw new Error(`user not found`) + throw new Error(`user ${userId} not found`) // TODO: fix logs doxing } return user } @@ -50,7 +50,7 @@ export default class { async UnbanUser(userId: string, txId?: string) { const affected = await this.dbs.Update('User', { user_id: userId }, { locked: false }, txId) if (!affected) { - throw new Error("unaffected user unlock") + throw new Error("unaffected user unlock for " + userId) // TODO: fix logs doxing } } @@ -58,7 +58,7 @@ export default class { const user = await this.GetUser(userId, txId) const affected = await this.dbs.Update('User', { user_id: userId }, { balance_sats: 0, locked: true }, txId) if (!affected) { - throw new Error("unaffected ban user") + throw new Error("unaffected ban user for " + userId) // TODO: fix logs doxing } if (user.balance_sats > 0) { this.eventsLog.LogEvent({ type: 'balance_decrement', userId, appId: "", appUserId: "", balance: user.balance_sats, data: 'ban', amount: user.balance_sats }) @@ -80,7 +80,7 @@ export default class { const affected = await this.dbs.Increment('User', { user_id: userId }, "balance_sats", increment, txId) if (!affected) { getLogger({ userId: userId, component: "balanceUpdates" })("user unaffected by increment") - throw new Error("unaffected balance increment") + throw new Error("unaffected balance increment for " + userId) // TODO: fix logs doxing } getLogger({ userId: userId, component: "balanceUpdates" })("incremented balance from", user.balance_sats, "sats, by", increment, "sats") this.eventsLog.LogEvent({ type: 'balance_increment', userId, appId: "", appUserId: "", balance: user.balance_sats, data: reason, amount: increment }) @@ -105,7 +105,7 @@ export default class { const affected = await this.dbs.Decrement('User', { user_id: userId }, "balance_sats", decrement, txId) if (!affected) { getLogger({ userId: userId, component: "balanceUpdates" })("user unaffected by decrement") - throw new Error("unaffected balance decrement") + throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing } getLogger({ userId: userId, component: "balanceUpdates" })("decremented balance from", user.balance_sats, "sats, by", decrement, "sats") this.eventsLog.LogEvent({ type: 'balance_decrement', userId, appId: "", appUserId: "", balance: user.balance_sats, data: reason, amount: decrement }) @@ -126,8 +126,4 @@ export default class { const lastSeenAtUnix = now - seconds return this.dbs.Find('UserAccess', { where: { last_seen_at_unix: LessThan(lastSeenAtUnix) } }) } - - async DeleteUserAccess(userId: string, txId?: string) { - return this.dbs.Delete('UserAccess', { user_id: userId }, txId) - } -} +} \ No newline at end of file