diff --git a/DOCKER.md b/DOCKER.md index 1e4bebae..f65fe41b 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -14,9 +14,55 @@ docker run -d \ --network host \ -p 1776:1776 \ -p 1777:1777 \ + -e DATA_DIR=/app/data \ -v /path/to/local/data:/app/data \ -v $HOME/.lnd:/root/.lnd \ ghcr.io/shocknet/lightning-pub:latest ``` Network host is used so the service can reach a local LND via localhost. LND is assumed to be under the users home folder, update these resources as needed. + +## Getting the Connection String + +After starting the container, you can get the connection string in several ways: + +### Option 1: From the mounted data directory + +If `DATA_DIR=/app/data` is set and the volume is mounted correctly, the connection string will be in: + +```ssh +cat /path/to/local/data/admin.connect +``` + +The connection string format is: `nprofile1...:token` + +### Option 2: Via API endpoint + +Access the wizard endpoint to get connection info: + +```ssh +curl http://localhost:1777/wizard/admin_connect_info +``` + +The response will include the `nprofile` and `admin_token`. Combine them as `nprofile:admin_token` to form the connection string. + +### Option 3: From inside the container + +If the files aren't in the mounted volume, check inside the container: + +```ssh +docker exec lightning-pub cat /app/data/admin.connect +``` + +Or if `DATA_DIR` wasn't set, check the working directory: + +```ssh +docker exec lightning-pub cat /app/admin.connect +``` + +### Troubleshooting + +If `/data` folder is empty: +- Ensure `DATA_DIR=/app/data` environment variable is set in the docker run command +- Check container logs: `docker logs lightning-pub` to see where files are being written +- The logs will show the configured data directory path at startup diff --git a/src/services/ShockPush/autogenerated/http_client.ts b/src/services/ShockPush/autogenerated/http_client.ts index 1a29dff6..ab3f4646 100644 --- a/src/services/ShockPush/autogenerated/http_client.ts +++ b/src/services/ShockPush/autogenerated/http_client.ts @@ -14,11 +14,18 @@ export type ClientParams = { checkResult?: true } export default (params: ClientParams) => ({ - EnrollServicePub: async (request: Types.ServiceNpub): Promise => { + EnrollServicePub: async (query: Types.EnrollServicePub_Query): Promise => { let finalRoute = '/api/admin/service/enroll' + const initialQuery = query as Record + const finalQuery: Record = {} + for (const key in initialQuery) + if (Array.isArray(initialQuery[key])) + finalQuery[key] = initialQuery[key].join(',') + const q = (new URLSearchParams(finalQuery)).toString() + finalRoute = finalRoute + (q === '' ? '' : '?' + q) const auth = await params.retrieveAdminAuth() if (auth === null) throw new Error('retrieveAdminAuth() returned null') - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { return data diff --git a/src/services/ShockPush/autogenerated/types.ts b/src/services/ShockPush/autogenerated/types.ts index c4908750..c9c310e9 100644 --- a/src/services/ShockPush/autogenerated/types.ts +++ b/src/services/ShockPush/autogenerated/types.ts @@ -25,7 +25,10 @@ export type NostrAppMethodInputs = SendNotification_Input export type NostrAppMethodOutputs = SendNotification_Output export type AuthContext = AdminContext | GuestContext | NostrAppContext -export type EnrollServicePub_Input = { rpcName: 'EnrollServicePub', req: ServiceNpub } +export type EnrollServicePub_Query = { + pubkey_hex?: string[] | string +} +export type EnrollServicePub_Input = { rpcName: 'EnrollServicePub', query: EnrollServicePub_Query } export type EnrollServicePub_Output = ResultError | { status: 'OK' } export type Health_Input = { rpcName: 'Health' } @@ -59,19 +62,27 @@ export const EmptyValidate = (o?: Empty, opts: EmptyOptions = {}, path: string = } export type Notification = { + body?: string data: string recipient_registration_tokens: string[] + title?: string } -export const NotificationOptionalFields: [] = [] +export type NotificationOptionalField = 'body' | 'title' +export const NotificationOptionalFields: NotificationOptionalField[] = ['body', 'title'] export type NotificationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] + checkOptionalsAreSet?: NotificationOptionalField[] + body_CustomCheck?: (v?: string) => boolean data_CustomCheck?: (v: string) => boolean recipient_registration_tokens_CustomCheck?: (v: string[]) => boolean + title_CustomCheck?: (v?: string) => boolean } export const NotificationValidate = (o?: Notification, opts: NotificationOptions = {}, path: string = 'Notification::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.body || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('body')) && typeof o.body !== 'string') return new Error(`${path}.body: is not a string`) + if (opts.body_CustomCheck && !opts.body_CustomCheck(o.body)) return new Error(`${path}.body: custom check failed`) + if (typeof o.data !== 'string') return new Error(`${path}.data: is not a string`) if (opts.data_CustomCheck && !opts.data_CustomCheck(o.data)) return new Error(`${path}.data: custom check failed`) @@ -81,6 +92,9 @@ export const NotificationValidate = (o?: Notification, opts: NotificationOptions } if (opts.recipient_registration_tokens_CustomCheck && !opts.recipient_registration_tokens_CustomCheck(o.recipient_registration_tokens)) return new Error(`${path}.recipient_registration_tokens: custom check failed`) + if ((o.title || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('title')) && typeof o.title !== 'string') return new Error(`${path}.title: is not a string`) + if (opts.title_CustomCheck && !opts.title_CustomCheck(o.title)) return new Error(`${path}.title: custom check failed`) + return null } diff --git a/src/services/ShockPush/index.ts b/src/services/ShockPush/index.ts index 8e84fd5e..7a88faa5 100644 --- a/src/services/ShockPush/index.ts +++ b/src/services/ShockPush/index.ts @@ -3,10 +3,12 @@ import { bytesToHex } from '@noble/hashes/utils' import { sha256 } from '@noble/hashes/sha256' import { base64 } from '@scure/base'; import NewClient, { ClientParams } from './autogenerated/http_client.js' +import * as Types from './autogenerated/types.js' import { ERROR, getLogger } from '../helpers/logger.js' const utf8Encoder = new TextEncoder() export type PushPair = { pubkey: string, privateKey: string } const nip98Kind = 27235 +export type ShockPushNotification = { message: string, body: string, title: string } export class ShockPush { private client: ReturnType private logger: ReturnType @@ -52,8 +54,11 @@ export class ShockPush { return nip98Header } - SendNotification = async (message: string, messagingTokens: string[]) => { - const res = await this.client.SendNotification({ recipient_registration_tokens: messagingTokens, data: message }) + SendNotification = async ({ body, message, title }: ShockPushNotification, messagingTokens: string[]) => { + const res = await this.client.SendNotification({ + recipient_registration_tokens: messagingTokens, data: message, + body, title + }) if (res.status !== 'OK') { this.logger(ERROR, `failed to send notification: ${res.status}`) } diff --git a/src/services/lnd/settings.ts b/src/services/lnd/settings.ts index 842cd57b..aff9777d 100644 --- a/src/services/lnd/settings.ts +++ b/src/services/lnd/settings.ts @@ -18,9 +18,9 @@ export type BalanceInfo = { channelsBalance: ChannelBalance[]; } -export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number, used: 'lnd' | 'provider' | 'internal') => Promise +export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number, used: 'lnd' | 'provider' | 'internal', broadcastHeight?: number) => Promise export type InvoicePaidCb = (paymentRequest: string, amount: number, used: 'lnd' | 'provider' | 'internal') => Promise -export type NewBlockCb = (height: number) => void +export type NewBlockCb = (height: number, skipMetrics?: boolean) => Promise export type HtlcCb = (event: HtlcEvent) => void export type ChannelEventCb = (event: ChannelEventUpdate, channels: Channel[]) => void diff --git a/src/services/main/appUserManager.ts b/src/services/main/appUserManager.ts index 9db8b5e6..168258f1 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 ${ctx.user_id} not found`) // TODO: fix logs doxing + throw new Error("app user not found") } const nostrSettings = this.settings.getSettings().nostrRelaySettings const { max, serviceFeeFloor, serviceFeeBps } = this.applicationManager.paymentManager.GetMaxPayableInvoice(user.balance_sats) @@ -183,4 +183,4 @@ export default class { } this.log("Cleaned up inactive users") } -} \ No newline at end of file +} diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 6f610878..3d885681 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -31,6 +31,7 @@ import { NotificationsManager } from "./notificationsManager.js" import { ApplicationUser } from '../storage/entity/ApplicationUser.js' import SettingsManager from './settingsManager.js' import { NostrSettings, AppInfo } from '../nostr/nostrPool.js' +import { ShockPushNotification } from '../ShockPush/index.js' type UserOperationsSub = { id: string newIncomingInvoice: (operation: Types.UserOperation) => void @@ -80,7 +81,7 @@ export default class { this.liquidityManager = new LiquidityManager(this.settings, this.storage, this.utils, this.liquidityProvider, this.lnd, this.rugPullTracker) this.metricsManager = new MetricsManager(this.storage, this.lnd) - this.paymentManager = new PaymentManager(this.storage, this.metricsManager, this.lnd, adminManager.swaps, this.settings, this.liquidityManager, this.utils, this.addressPaidCb, this.invoicePaidCb) + this.paymentManager = new PaymentManager(this.storage, this.metricsManager, this.lnd, adminManager.swaps, this.settings, this.liquidityManager, this.utils, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb) this.productManager = new ProductManager(this.storage, this.paymentManager, this.settings) this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager) this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager) @@ -153,18 +154,20 @@ export default class { this.metricsManager.HtlcCb(e) } - newBlockCb: NewBlockCb = (height) => { - this.NewBlockHandler(height) + newBlockCb: NewBlockCb = (height, skipMetrics) => { + return this.NewBlockHandler(height, skipMetrics) } - NewBlockHandler = async (height: number) => { + NewBlockHandler = async (height: number, skipMetrics?: boolean) => { let confirmed: (PendingTx & { confs: number; })[] let log = getLogger({}) this.storage.paymentStorage.DeleteExpiredTransactionSwaps(height) .catch(err => log(ERROR, "failed to delete expired transaction swaps", err.message || err)) try { const balanceEvents = await this.paymentManager.GetLndBalance() - await this.metricsManager.NewBlockCb(height, balanceEvents) + if (!skipMetrics) { + await this.metricsManager.NewBlockCb(height, balanceEvents) + } confirmed = await this.paymentManager.CheckNewlyConfirmedTxs(height) await this.liquidityManager.onNewBlock() } catch (err: any) { @@ -203,7 +206,7 @@ export default class { })) } - addressPaidCb: AddressPaidCb = (txOutput, address, amount, used) => { + addressPaidCb: AddressPaidCb = (txOutput, address, amount, used, broadcastHeight) => { return this.storage.StartTransaction(async tx => { // On-chain payments not supported when bypass is enabled if (this.liquidityProvider.getSettings().useOnlyLiquidityProvider) { @@ -231,7 +234,8 @@ export default class { const fee = this.paymentManager.getReceiveServiceFee(Types.UserOperationType.INCOMING_TX, amount, isManagedUser) try { // This call will fail if the transaction is already registered - const addedTx = await this.storage.paymentStorage.AddAddressReceivingTransaction(userAddress, txOutput.hash, txOutput.index, amount, fee, internal, blockHeight, tx) + const txBroadcastHeight = broadcastHeight ? broadcastHeight : blockHeight + const addedTx = await this.storage.paymentStorage.AddAddressReceivingTransaction(userAddress, txOutput.hash, txOutput.index, amount, fee, internal, txBroadcastHeight, tx) if (internal) { const addressData = `${address}:${txOutput.hash}` this.storage.eventsLog.LogEvent({ type: 'address_paid', userId: userAddress.user.user_id, appId: userAddress.linkedApplication.app_id, appUserId: "", balance: userAddress.user.balance_sats, data: addressData, amount }) @@ -381,10 +385,36 @@ export default class { { operation: op, requestId: "GetLiveUserOperations", status: 'OK', latest_balance: balance } const j = JSON.stringify(message) this.utils.nostrSender.Send({ type: 'app', appId: app.app_id }, { type: 'content', content: j, pub: user.nostr_public_key }) - this.SendEncryptedNotification(app, user, op) + + this.SendEncryptedNotification(app, user, op, this.getOperationMessage(op)) } - async SendEncryptedNotification(app: Application, appUser: ApplicationUser, op: Types.UserOperation) { + getOperationMessage = (op: Types.UserOperation) => { + switch (op.type) { + case Types.UserOperationType.INCOMING_TX: + case Types.UserOperationType.INCOMING_INVOICE: + case Types.UserOperationType.INCOMING_USER_TO_USER: + return { + body: "You received a new payment", + title: "Payment Received" + } + case Types.UserOperationType.OUTGOING_TX: + case Types.UserOperationType.OUTGOING_INVOICE: + case Types.UserOperationType.OUTGOING_USER_TO_USER: + return { + body: "You sent a new payment", + title: "Payment Sent" + } + + default: + return { + body: "Unknown operation", + title: "Unknown Operation" + } + } + } + + async SendEncryptedNotification(app: Application, appUser: ApplicationUser, op: Types.UserOperation, { body, title }: { body: string, title: string }) { const devices = await this.storage.applicationStorage.GetAppUserDevices(appUser.identifier) if (devices.length === 0 || !app.nostr_public_key || !app.nostr_private_key || !appUser.nostr_public_key) { return @@ -394,8 +424,12 @@ export default class { const j = JSON.stringify(op) const encrypted = nip44.encrypt(j, ck) const encryptedData: { encrypted: string, app_npub_hex: string } = { encrypted, app_npub_hex: app.nostr_public_key } - - this.notificationsManager.SendNotification(JSON.stringify(encryptedData), tokens, { + const notification: ShockPushNotification = { + message: JSON.stringify(encryptedData), + body, + title + } + await this.notificationsManager.SendNotification(notification, tokens, { pubkey: app.nostr_public_key!, privateKey: app.nostr_private_key! }) diff --git a/src/services/main/notificationsManager.ts b/src/services/main/notificationsManager.ts index 4e3602b0..b639b716 100644 --- a/src/services/main/notificationsManager.ts +++ b/src/services/main/notificationsManager.ts @@ -1,4 +1,4 @@ -import { PushPair, ShockPush } from "../ShockPush/index.js" +import { PushPair, ShockPush, ShockPushNotification } from "../ShockPush/index.js" import { getLogger, PubLogger } from "../helpers/logger.js" import SettingsManager from "./settingsManager.js" @@ -21,12 +21,12 @@ export class NotificationsManager { return newClient } - SendNotification = async (message: string, messagingTokens: string[], pair: PushPair) => { + SendNotification = async (notification: ShockPushNotification, messagingTokens: string[], pair: PushPair) => { if (!this.settings.getSettings().serviceSettings.shockPushBaseUrl) { this.logger("ShockPush is not configured, skipping notification") return } const client = this.getClient(pair) - await client.SendNotification(message, messagingTokens) + await client.SendNotification(notification, messagingTokens) } } \ No newline at end of file diff --git a/src/services/main/paymentManager.ts b/src/services/main/paymentManager.ts index 82610061..ec351091 100644 --- a/src/services/main/paymentManager.ts +++ b/src/services/main/paymentManager.ts @@ -6,7 +6,7 @@ import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorag import LND from '../lnd/lnd.js' import { Application } from '../storage/entity/Application.js' import { ERROR, getLogger, PubLogger } from '../helpers/logger.js' -import { AddressPaidCb, InvoicePaidCb } from '../lnd/settings.js' +import { AddressPaidCb, InvoicePaidCb, NewBlockCb } from '../lnd/settings.js' import { UserReceivingInvoice, ZapInfo } from '../storage/entity/UserReceivingInvoice.js' import { Payment_PaymentStatus } from '../../../proto/lnd/lightning.js' import { Event, verifiedSymbol, verifyEvent } from 'nostr-tools' @@ -54,6 +54,7 @@ export default class { lnd: LND addressPaidCb: AddressPaidCb invoicePaidCb: InvoicePaidCb + newBlockCb: NewBlockCb log = getLogger({ component: "PaymentManager" }) watchDog: Watchdog liquidityManager: LiquidityManager @@ -61,7 +62,7 @@ export default class { swaps: Swaps invoiceLock: InvoiceLock metrics: Metrics - constructor(storage: Storage, metrics: Metrics, lnd: LND, swaps: Swaps, settings: SettingsManager, liquidityManager: LiquidityManager, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) { + constructor(storage: Storage, metrics: Metrics, lnd: LND, swaps: Swaps, settings: SettingsManager, liquidityManager: LiquidityManager, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb) { this.storage = storage this.metrics = metrics this.settings = settings @@ -72,6 +73,7 @@ export default class { this.swaps = swaps this.addressPaidCb = addressPaidCb this.invoicePaidCb = invoicePaidCb + this.newBlockCb = newBlockCb this.invoiceLock = new InvoiceLock() } @@ -185,24 +187,39 @@ export default class { } try { - const { txs, currentHeight, lndPubkey } = await this.getLatestTransactions(log) + const { txs, currentHeight, lndPubkey, startHeight } = await this.getLatestTransactions(log) - const recoveredCount = await this.processMissedChainTransactions(txs, log) + const recoveredCount = await this.processMissedChainTransactions(txs, log, startHeight) // Update latest checked height to current block height await this.storage.liquidityStorage.UpdateLatestCheckedHeight('lnd', lndPubkey, currentHeight) if (recoveredCount > 0) { - log(`processed ${recoveredCount} missed chain tx(s)`) + log(`processed ${recoveredCount} missed chain tx(s) triggering new block callback`) + // Call new block callback to process any new transaction that was just added to the database as pending + await this.newBlockCb(currentHeight, true) } 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) } } - private async getLatestTransactions(log: PubLogger): Promise<{ txs: Transaction[], currentHeight: number, lndPubkey: string }> { + 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 @@ -212,10 +229,10 @@ export default class { const { transactions } = await this.lnd.GetTransactions(startHeight) log(`retrieved ${transactions.length} transactions from LND`) - return { txs: transactions, currentHeight: lndInfo.blockHeight, lndPubkey } + return { txs: transactions, currentHeight: lndInfo.blockHeight, lndPubkey, startHeight } } - private async processMissedChainTransactions(transactions: Transaction[], log: PubLogger): Promise { + private async processMissedChainTransactions(transactions: Transaction[], log: PubLogger, startHeight: number): Promise { let recoveredCount = 0 const addresses = await this.lnd.ListAddresses() for (const tx of transactions) { @@ -231,7 +248,7 @@ export default class { continue } - const processed = await this.processUserAddressOutput(output, tx, log) + const processed = await this.processUserAddressOutput(output, tx, log, startHeight) if (processed) { recoveredCount++ } @@ -272,7 +289,7 @@ export default class { return true } - private async processUserAddressOutput(output: OutputDetail, tx: Transaction, log: PubLogger) { + private async processUserAddressOutput(output: OutputDetail, tx: Transaction, log: PubLogger, startHeight: number) { const existingTx = await this.storage.paymentStorage.GetAddressReceivingTransactionOwner( output.address, tx.txHash @@ -285,7 +302,7 @@ 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}`) - this.addressPaidCb({ hash: tx.txHash, index: outputIndex }, output.address, amount, 'lnd') + 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 } diff --git a/src/services/storage/userStorage.ts b/src/services/storage/userStorage.ts index 58dd6cf5..d3453346 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 ${userId} not found`) // TODO: fix logs doxing + throw new Error(`user not found`) } 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 for " + userId) // TODO: fix logs doxing + throw new Error("unaffected user unlock") } } @@ -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 for " + userId) // TODO: fix logs doxing + throw new Error("unaffected ban user") } 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 for " + userId) // TODO: fix logs doxing + throw new Error("unaffected balance increment") } 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 for " + userId) // TODO: fix logs doxing + throw new Error("unaffected balance decrement") } 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,4 +126,4 @@ export default class { const lastSeenAtUnix = now - seconds return this.dbs.Find('UserAccess', { where: { last_seen_at_unix: LessThan(lastSeenAtUnix) } }) } -} \ No newline at end of file +} diff --git a/src/tests/networkSetup.ts b/src/tests/networkSetup.ts index 38a2e0fb..33277f0e 100644 --- a/src/tests/networkSetup.ts +++ b/src/tests/networkSetup.ts @@ -26,8 +26,8 @@ export const setupNetwork = async (): Promise => { const lndNodeSettings = LoadLndNodeSettingsFromEnv({}) const secondLndNodeSettings = LoadSecondLndSettingsFromEnv() const liquiditySettings: LiquiditySettings = { disableLiquidityProvider: true, liquidityProviderPub: "", useOnlyLiquidityProvider: false, providerRelayUrl: "" } - const alice = new LND(() => ({ lndSettings, lndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) - const bob = new LND(() => ({ lndSettings, lndNodeSettings: secondLndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) + const alice = new LND(() => ({ lndSettings, lndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, async () => { }, () => { }, () => { }) + const bob = new LND(() => ({ lndSettings, lndNodeSettings: secondLndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, async () => { }, () => { }, () => { }) await tryUntil(async i => { const peers = await alice.ListPeers() if (peers.peers.length > 0) { diff --git a/src/tests/testBase.ts b/src/tests/testBase.ts index 791bb6ce..ef06aeda 100644 --- a/src/tests/testBase.ts +++ b/src/tests/testBase.ts @@ -89,12 +89,12 @@ export const SetupTest = async (d: Describe, chainTools: ChainTools): Promise ({ lndSettings, lndNodeSettings: secondLndNodeSettings }) - const externalAccessToOtherLnd = new LND(otherLndSetting, new LiquidityProvider(() => liquiditySettings, extermnalUtils, async () => { }, async () => { }), async () => { }, extermnalUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) + const externalAccessToOtherLnd = new LND(otherLndSetting, new LiquidityProvider(() => liquiditySettings, extermnalUtils, async () => { }, async () => { }), async () => { }, extermnalUtils, async () => { }, async () => { }, async () => { }, () => { }, () => { }) await externalAccessToOtherLnd.Warmup() const thirdLndNodeSettings = LoadThirdLndSettingsFromEnv() const thirdLndSetting = () => ({ lndSettings, lndNodeSettings: thirdLndNodeSettings }) - const externalAccessToThirdLnd = new LND(thirdLndSetting, new LiquidityProvider(() => liquiditySettings, extermnalUtils, async () => { }, async () => { }), async () => { }, extermnalUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) + const externalAccessToThirdLnd = new LND(thirdLndSetting, new LiquidityProvider(() => liquiditySettings, extermnalUtils, async () => { }, async () => { }), async () => { }, extermnalUtils, async () => { }, async () => { }, async () => { }, () => { }, () => { }) await externalAccessToThirdLnd.Warmup()