From 18f7c5837ba61c09f919b92287382e58206b84f6 Mon Sep 17 00:00:00 2001 From: Juan P Lopez Date: Wed, 27 Nov 2024 22:08:52 -0500 Subject: [PATCH 1/5] chore: add settle pending onchain payments script --- .../debug/settle-pending-onchain-payments.ts | 117 ++++++++++++++++++ .../domain/bitcoin/onchain/index.types.d.ts | 4 + core/api/src/domain/ledger/index.types.d.ts | 4 + core/api/src/services/bria/grpc-client.ts | 6 + core/api/src/services/bria/index.ts | 11 +- core/api/src/services/ledger/index.ts | 19 +++ 6 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 core/api/src/debug/settle-pending-onchain-payments.ts diff --git a/core/api/src/debug/settle-pending-onchain-payments.ts b/core/api/src/debug/settle-pending-onchain-payments.ts new file mode 100644 index 0000000000..534f86f4a9 --- /dev/null +++ b/core/api/src/debug/settle-pending-onchain-payments.ts @@ -0,0 +1,117 @@ +/** + * how to run: + * + * pnpm tsx src/debug/void-onchain-payment.ts + * + * : journal id to void. + * : bria payout id + */ + +import { Wallets } from "@/app" + +import { OnChainService } from "@/services/bria" +import { LedgerService } from "@/services/ledger" +import * as LedgerFacade from "@/services/ledger/facade" +import { lndsConnect } from "@/services/lnd/auth" +import { isUp } from "@/services/lnd/health" +import { setupMongoConnection } from "@/services/mongodb" + +const onChainService = OnChainService() + +const processPayment = async (payment: LedgerTransaction) => { + const payout = await onChainService.findPayoutByLedgerJournalId(payment.journalId) + if (payout instanceof Error) { + return new Error(`Failed to get payout: ${payout.name} - ${payout.message}`) + } + if (!payout.batchId || !payout.txId || !payout.vout) { + return new Error("Missing required payout details") + } + + const setTxIdResult = await LedgerFacade.setOnChainTxIdByPayoutId({ + payoutId: payout.id, + txId: payout.txId, + vout: payout.vout, + }) + if (setTxIdResult instanceof Error) { + return new Error( + `Failed to set transaction ID: ${setTxIdResult.name} - ${setTxIdResult.message}`, + ) + } + + const settledPayout = await Wallets.settlePayout(payout.id) + if (settledPayout instanceof Error) { + return new Error( + `Failed to settle payout: ${settledPayout.name} - ${settledPayout.message}`, + ) + } + + return true +} + +const settlePendingOnchainPayments = async () => { + const pendingPayments = LedgerService().listPendingOnchainPayments() + if (pendingPayments instanceof Error) return pendingPayments + + let totalPayments = 0 + let successCount = 0 + let errorCount = 0 + const errors = [] + + for await (const payment of pendingPayments) { + totalPayments++ + console.log(`Processing payment ${totalPayments}`) + + const result = await processPayment(payment) + if (result instanceof Error) { + errorCount++ + errors.push({ + journalId: payment.journalId, + payoutId: payment.payoutId, + error: result.message, + }) + console.error(`Failed to process payment: ${result.message}`) + continue + } + + successCount++ + console.log( + `Successfully processed payout ${payment.payoutId} for journal ${payment.journalId}`, + ) + } + + return { + successCount, + errorCount, + total: totalPayments, + errors, + } +} + +const main = async () => { + const result = await settlePendingOnchainPayments() + if (result instanceof Error) { + console.error("Error:", result) + return + } + console.log("Settlement process completed") + console.log(`Total Processed: ${result.total}`) + console.log(`Successful: ${result.successCount}`) + console.log(`Failed: ${result.errorCount}`) + + if (result.errors.length > 0) { + console.log("\nErrors:") + result.errors.forEach(({ journalId, payoutId, error }) => { + console.log( + `- Journal ${journalId}${payoutId ? ` (Payout ${payoutId})` : ""}: ${error}`, + ) + }) + } +} + +setupMongoConnection() + .then(async (mongoose) => { + await Promise.all(lndsConnect.map((lndParams) => isUp(lndParams))) + await main() + if (mongoose) await mongoose.connection.close() + }) + .catch((err) => console.log(err)) diff --git a/core/api/src/domain/bitcoin/onchain/index.types.d.ts b/core/api/src/domain/bitcoin/onchain/index.types.d.ts index f676f9c41c..fcdc912c49 100644 --- a/core/api/src/domain/bitcoin/onchain/index.types.d.ts +++ b/core/api/src/domain/bitcoin/onchain/index.types.d.ts @@ -10,6 +10,7 @@ type OnChainAddressRequestId = string & { readonly brand: unique symbol } type BlockId = string & { readonly brand: unique symbol } type OnChainTxHash = string & { readonly brand: unique symbol } type PayoutId = string & { readonly brand: unique symbol } +type BatchId = string & { readonly brand: unique symbol } type OnChainTxVout = number & { readonly brand: unique symbol } type ScanDepth = number & { readonly brand: unique symbol } type TxOut = { @@ -92,6 +93,9 @@ type OnChainPayout = { id: PayoutId journalId: LedgerJournalId batchInclusionEstimatedAt: number | undefined + batchId: BatchId | undefined + txId: OnChainTxHash | undefined + vout: OnChainTxVout | undefined } type OnChainEventHandler = (event: OnChainEvent) => true | ApplicationError diff --git a/core/api/src/domain/ledger/index.types.d.ts b/core/api/src/domain/ledger/index.types.d.ts index 53f05a8481..72eb14dbf7 100644 --- a/core/api/src/domain/ledger/index.types.d.ts +++ b/core/api/src/domain/ledger/index.types.d.ts @@ -330,6 +330,10 @@ interface ILedgerService { listWalletIdsWithPendingPayments: () => AsyncGenerator | LedgerServiceError + listPendingOnchainPayments: () => + | AsyncGenerator> + | LedgerServiceError + addColdStorageTxReceive( args: AddColdStorageTxReceiveArgs, ): Promise diff --git a/core/api/src/services/bria/grpc-client.ts b/core/api/src/services/bria/grpc-client.ts index 4bfea11c12..8c87c447a5 100644 --- a/core/api/src/services/bria/grpc-client.ts +++ b/core/api/src/services/bria/grpc-client.ts @@ -7,6 +7,8 @@ import { EstimatePayoutFeeResponse, GetAddressRequest, GetAddressResponse, + GetBatchRequest, + GetBatchResponse, GetPayoutRequest, GetPayoutResponse, GetWalletBalanceSummaryRequest, @@ -58,3 +60,7 @@ export const estimatePayoutFee = promisify< >(bitcoinBridgeClient.estimatePayoutFee.bind(bitcoinBridgeClient)) export const subscribeAll = bitcoinBridgeClient.subscribeAll.bind(bitcoinBridgeClient) + +export const getBatch = promisify( + bitcoinBridgeClient.getBatch.bind(bitcoinBridgeClient), +) diff --git a/core/api/src/services/bria/index.ts b/core/api/src/services/bria/index.ts index fa1bd74658..374b5ed13b 100644 --- a/core/api/src/services/bria/index.ts +++ b/core/api/src/services/bria/index.ts @@ -233,16 +233,15 @@ export const OnChainService = (): IOnChainService => { const response = await getPayout(request, metadata) const foundPayout = response.getPayout() - if (foundPayout === undefined) return new PayoutNotFoundError() - let batchInclusionEstimatedAt = undefined - if (foundPayout.hasBatchInclusionEstimatedAt()) { - batchInclusionEstimatedAt = foundPayout.getBatchInclusionEstimatedAt() - } + return { id: foundPayout.getId() as PayoutId, journalId: foundPayout.getExternalId() as LedgerJournalId, - batchInclusionEstimatedAt, + batchInclusionEstimatedAt: foundPayout.getBatchInclusionEstimatedAt(), + batchId: foundPayout.getBatchId() as BatchId, + txId: foundPayout.getTxId() as OnChainTxHash, + vout: foundPayout.getVout() as OnChainTxVout, } } catch (err) { if ( diff --git a/core/api/src/services/ledger/index.ts b/core/api/src/services/ledger/index.ts index e6f71b316e..cf91b46f0f 100644 --- a/core/api/src/services/ledger/index.ts +++ b/core/api/src/services/ledger/index.ts @@ -493,6 +493,24 @@ export const LedgerService = (): ILedgerService => { } } + const listPendingOnchainPayments = async function* (): + | AsyncGenerator> + | LedgerServiceError { + try { + const transactions = Transaction.find({ + type: LedgerTransactionType.OnchainPayment, + pending: true, + account_path: liabilitiesMainAccount, + }).cursor({ batchSize: 100 }) + + for await (const tx of transactions) { + yield translateToLedgerTx(tx) + } + } catch (error) { + return new UnknownLedgerError(error) + } + } + return wrapAsyncFunctionsToRunInSpan({ namespace: "services.ledger", fns: { @@ -516,6 +534,7 @@ export const LedgerService = (): ILedgerService => { isLnTxRecorded, getWalletIdByPaymentHash, listWalletIdsWithPendingPayments, + listPendingOnchainPayments, ...admin, ...send, }, From 44c915e20cae068442d6d8ece962df41876a6294 Mon Sep 17 00:00:00 2001 From: Juan P Lopez Date: Wed, 27 Nov 2024 22:12:51 -0500 Subject: [PATCH 2/5] fix: how to run comment --- core/api/src/debug/settle-pending-onchain-payments.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/api/src/debug/settle-pending-onchain-payments.ts b/core/api/src/debug/settle-pending-onchain-payments.ts index 534f86f4a9..2035076435 100644 --- a/core/api/src/debug/settle-pending-onchain-payments.ts +++ b/core/api/src/debug/settle-pending-onchain-payments.ts @@ -1,10 +1,8 @@ /** * how to run: * - * pnpm tsx src/debug/void-onchain-payment.ts + * pnpm tsx src/debug/settle-pending-onchain-payments.ts * - * : journal id to void. - * : bria payout id */ import { Wallets } from "@/app" From 3322841cb126ba0e5ce80ae0e054f9158fdb9459 Mon Sep 17 00:00:00 2001 From: Juan P Lopez Date: Wed, 27 Nov 2024 22:19:49 -0500 Subject: [PATCH 3/5] fix: lint issues --- core/api/src/services/bria/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/api/src/services/bria/index.ts b/core/api/src/services/bria/index.ts index 374b5ed13b..129e2e9f60 100644 --- a/core/api/src/services/bria/index.ts +++ b/core/api/src/services/bria/index.ts @@ -280,6 +280,9 @@ export const OnChainService = (): IOnChainService => { id: response.getId() as PayoutId, journalId, batchInclusionEstimatedAt: response.getBatchInclusionEstimatedAt(), + batchId: undefined, + txId: undefined, + vout: undefined, } } catch (err) { const errMsg = parseErrorMessageFromUnknown(err) From 2e2f06eccc27dc74e3d49056f4d1733dee05a9a1 Mon Sep 17 00:00:00 2001 From: Juan P Lopez Date: Sat, 30 Nov 2024 12:30:11 -0500 Subject: [PATCH 4/5] fix: handle proto generator default values issue --- core/api/src/debug/settle-pending-onchain-payments.ts | 2 +- core/api/src/services/bria/index.ts | 6 ++++-- core/api/src/services/ledger/index.ts | 11 +++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/core/api/src/debug/settle-pending-onchain-payments.ts b/core/api/src/debug/settle-pending-onchain-payments.ts index 2035076435..28c8cbfb73 100644 --- a/core/api/src/debug/settle-pending-onchain-payments.ts +++ b/core/api/src/debug/settle-pending-onchain-payments.ts @@ -21,7 +21,7 @@ const processPayment = async (payment: LedgerTransaction) => { if (payout instanceof Error) { return new Error(`Failed to get payout: ${payout.name} - ${payout.message}`) } - if (!payout.batchId || !payout.txId || !payout.vout) { + if (!payout.batchId || !payout.txId || payout.vout === undefined) { return new Error("Missing required payout details") } diff --git a/core/api/src/services/bria/index.ts b/core/api/src/services/bria/index.ts index 129e2e9f60..7e061e4d45 100644 --- a/core/api/src/services/bria/index.ts +++ b/core/api/src/services/bria/index.ts @@ -235,13 +235,15 @@ export const OnChainService = (): IOnChainService => { const foundPayout = response.getPayout() if (foundPayout === undefined) return new PayoutNotFoundError() + //fix issue with proto gen default values + const txId = (foundPayout.getTxId() as OnChainTxHash) || undefined return { id: foundPayout.getId() as PayoutId, journalId: foundPayout.getExternalId() as LedgerJournalId, batchInclusionEstimatedAt: foundPayout.getBatchInclusionEstimatedAt(), batchId: foundPayout.getBatchId() as BatchId, - txId: foundPayout.getTxId() as OnChainTxHash, - vout: foundPayout.getVout() as OnChainTxVout, + txId, + vout: txId ? (foundPayout.getVout() as OnChainTxVout) : undefined, } } catch (err) { if ( diff --git a/core/api/src/services/ledger/index.ts b/core/api/src/services/ledger/index.ts index cf91b46f0f..5361d52852 100644 --- a/core/api/src/services/ledger/index.ts +++ b/core/api/src/services/ledger/index.ts @@ -497,10 +497,21 @@ export const LedgerService = (): ILedgerService => { | AsyncGenerator> | LedgerServiceError { try { + const bankOwnerWalletId = await caching.getBankOwnerWalletId() + const dealerUsdWalletId = await caching.getDealerUsdWalletId() + const dealerBtcWalletId = await caching.getDealerBtcWalletId() + + const excludedAccounts = [ + toLiabilitiesWalletId(bankOwnerWalletId), + toLiabilitiesWalletId(dealerUsdWalletId), + toLiabilitiesWalletId(dealerBtcWalletId), + ] + const transactions = Transaction.find({ type: LedgerTransactionType.OnchainPayment, pending: true, account_path: liabilitiesMainAccount, + accounts: { $nin: excludedAccounts }, }).cursor({ batchSize: 100 }) for await (const tx of transactions) { From 9680600f6b1b27c51d21c053a7f1312711ecfe29 Mon Sep 17 00:00:00 2001 From: Juan P Lopez Date: Sat, 30 Nov 2024 12:34:52 -0500 Subject: [PATCH 5/5] fix: spell lint --- typos.toml | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/typos.toml b/typos.toml index 80fb7530c2..768d4665a5 100644 --- a/typos.toml +++ b/typos.toml @@ -1,27 +1,24 @@ files.extend-exclude = [ - "dev", - "core/api/dev", - "core/api/src/domain/users/languages.ts", - "core/api/docker-compose.yml", - "quickstart/*.yml", - "quickstart/galoy", - "quickstart/dev", - "prelude", - "core/notifications/locales/*.yml", - "apps/admin-panel/components/notification/languages.ts", - "apps/pay/components/success-animation.json", + "dev", + "core/api/dev", + "core/api/src/domain/users/languages.ts", + "core/api/docker-compose.yml", + "quickstart/*.yml", + "quickstart/galoy", + "quickstart/dev", + "prelude", + "core/notifications/locales/*.yml", + "apps/admin-panel/components/notification/languages.ts", + "apps/pay/components/success-animation.json", ] -default.extend-ignore-identifiers-re = [ - "^bc1\\w+", - "^lnbc\\w+", - "[Ww][Ss]", -] +default.extend-ignore-identifiers-re = ["^bc1\\w+", "^lnbc\\w+", "[Ww][Ss]"] -default.extend-ignore-re = ["\"eyJ[a-zA-Z0-9_\\-\\.]+\"", - "moneyImportantGovernement", - "GovernementCanPrintMoney", - "moneySocialAggrement", +default.extend-ignore-re = [ + "\"eyJ[a-zA-Z0-9_\\-\\.]+\"", + "moneyImportantGovernement", + "GovernementCanPrintMoney", + "moneySocialAggrement", ] [default.extend-words] @@ -29,3 +26,4 @@ default.extend-ignore-re = ["\"eyJ[a-zA-Z0-9_\\-\\.]+\"", Ons = "Ons" Lsat = "Lsat" quizs = "quizs" +nin = "nin"