lsp
This commit is contained in:
parent
c60547b7bb
commit
3c6dc7c962
9 changed files with 293 additions and 20 deletions
|
|
@ -30,6 +30,12 @@ LIQUIDITY_PROVIDER_PUB=
|
||||||
# Will execute when it costs less than 1% of balance and uses a trusted peer
|
# Will execute when it costs less than 1% of balance and uses a trusted peer
|
||||||
#BOOTSTRAP=1
|
#BOOTSTRAP=1
|
||||||
|
|
||||||
|
#LSP
|
||||||
|
OLYMPUS_LSP_URL=
|
||||||
|
VOLTAGE_LSP_URL=
|
||||||
|
LSP_CHANNEL_THRESHOLD=0
|
||||||
|
LSP_MAX_FEE_BPS=0
|
||||||
|
|
||||||
#ROOT_FEES
|
#ROOT_FEES
|
||||||
# Applied to either debits or credits and sent to an admin account
|
# Applied to either debits or credits and sent to an admin account
|
||||||
# BPS are basis points, 100 BPS = 1%
|
# BPS are basis points, 100 BPS = 1%
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { EnvMustBeNonEmptyString, EnvMustBeInteger, EnvCanBeBoolean, EnvCanBeInteger } from '../helpers/envParser.js'
|
import { EnvMustBeNonEmptyString, EnvMustBeInteger, EnvCanBeBoolean, EnvCanBeInteger } from '../helpers/envParser.js'
|
||||||
|
import { LoadLiquiditySettingsFromEnv } from './liquidityManager.js'
|
||||||
import { LndSettings } from './settings.js'
|
import { LndSettings } from './settings.js'
|
||||||
export const LoadLndSettingsFromEnv = (): LndSettings => {
|
export const LoadLndSettingsFromEnv = (): LndSettings => {
|
||||||
const lndAddr = process.env.LND_ADDRESS || "127.0.0.1:10009"
|
const lndAddr = process.env.LND_ADDRESS || "127.0.0.1:10009"
|
||||||
|
|
@ -7,6 +8,6 @@ export const LoadLndSettingsFromEnv = (): LndSettings => {
|
||||||
const feeRateLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_BPS", 60) / 10000
|
const feeRateLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_BPS", 60) / 10000
|
||||||
const feeFixedLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_EXTRA_SATS", 100)
|
const feeFixedLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_EXTRA_SATS", 100)
|
||||||
const mockLnd = EnvCanBeBoolean("MOCK_LND")
|
const mockLnd = EnvCanBeBoolean("MOCK_LND")
|
||||||
const liquidityProviderPub = process.env.LIQUIDITY_PROVIDER_PUB || ""
|
const liquiditySettings = LoadLiquiditySettingsFromEnv()
|
||||||
return { mainNode: { lndAddr, lndCertPath, lndMacaroonPath }, feeRateLimit, feeFixedLimit, mockLnd, liquidityProviderPub, useOnlyLiquidityProvider: false }
|
return { mainNode: { lndAddr, lndCertPath, lndMacaroonPath }, feeRateLimit, feeFixedLimit, mockLnd, liquiditySettings }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
52
src/services/lnd/liquidityManager.ts
Normal file
52
src/services/lnd/liquidityManager.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { getLogger } from "../helpers/logger.js"
|
||||||
|
import { LiquidityProvider } from "./liquidityProvider.js"
|
||||||
|
import LND from "./lnd.js"
|
||||||
|
import { LoadLSPSettingsFromEnv, LSPSettings, OlympusLSP, VoltageLSP } from "./lsp.js"
|
||||||
|
export type LiquiditySettings = {
|
||||||
|
lspSettings: LSPSettings
|
||||||
|
liquidityProviderPub: string
|
||||||
|
useOnlyLiquidityProvider: boolean
|
||||||
|
}
|
||||||
|
export const LoadLiquiditySettingsFromEnv = (): LiquiditySettings => {
|
||||||
|
const lspSettings = LoadLSPSettingsFromEnv()
|
||||||
|
const liquidityProviderPub = process.env.LIQUIDITY_PROVIDER_PUB || ""
|
||||||
|
return { lspSettings, liquidityProviderPub, useOnlyLiquidityProvider: false }
|
||||||
|
}
|
||||||
|
export class LiquidityManager {
|
||||||
|
settings: LiquiditySettings
|
||||||
|
liquidityProvider: LiquidityProvider
|
||||||
|
lnd: LND
|
||||||
|
olympusLSP: OlympusLSP
|
||||||
|
voltageLSP: VoltageLSP
|
||||||
|
log = getLogger({ component: "liquidityManager" })
|
||||||
|
channelRequested = false
|
||||||
|
constructor(settings: LiquiditySettings, liquidityProvider: LiquidityProvider, lnd: LND) {
|
||||||
|
this.settings = settings
|
||||||
|
this.liquidityProvider = liquidityProvider
|
||||||
|
this.lnd = lnd
|
||||||
|
this.olympusLSP = new OlympusLSP(settings.lspSettings, lnd, liquidityProvider)
|
||||||
|
this.voltageLSP = new VoltageLSP(settings.lspSettings, lnd, liquidityProvider)
|
||||||
|
}
|
||||||
|
beforeInvoiceCreation = async () => { }
|
||||||
|
afterInInvoicePaid = async () => {
|
||||||
|
if (this.channelRequested) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const olympusOk = await this.olympusLSP.openChannelIfReady()
|
||||||
|
if (olympusOk) {
|
||||||
|
this.log("requested channel from olympus")
|
||||||
|
this.channelRequested = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const voltageOk = await this.voltageLSP.openChannelIfReady()
|
||||||
|
if (voltageOk) {
|
||||||
|
this.log("requested channel from voltage")
|
||||||
|
this.channelRequested = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.log("no channel requested")
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeOutInvoicePayment = async () => { }
|
||||||
|
afterOutInvoicePaid = async () => { }
|
||||||
|
}
|
||||||
|
|
@ -81,7 +81,7 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async ShouldUseLiquidityProvider(req: LiquidityRequest): Promise<boolean> {
|
async ShouldUseLiquidityProvider(req: LiquidityRequest): Promise<boolean> {
|
||||||
if (this.settings.useOnlyLiquidityProvider) {
|
if (this.settings.liquiditySettings.useOnlyLiquidityProvider) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (!this.liquidProvider.CanProviderHandle(req)) {
|
if (!this.liquidProvider.CanProviderHandle(req)) {
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,235 @@
|
||||||
import fetch from "node-fetch"
|
import fetch from "node-fetch"
|
||||||
|
import { LiquidityProvider } from "./liquidityProvider.js"
|
||||||
|
import { getLogger, PubLogger } from '../helpers/logger.js'
|
||||||
|
import LND from "./lnd.js"
|
||||||
|
import { AddressType } from "../../../proto/autogenerated/ts/types.js"
|
||||||
|
import { EnvCanBeInteger } from "../helpers/envParser.js"
|
||||||
|
export type LSPSettings = {
|
||||||
|
olympusServiceUrl: string
|
||||||
|
voltageServiceUrl: string
|
||||||
|
channelThreshold: number
|
||||||
|
maxRelativeFee: number
|
||||||
|
}
|
||||||
|
|
||||||
export class LSP {
|
export const LoadLSPSettingsFromEnv = (): LSPSettings => {
|
||||||
serviceUrl: string
|
const olympusServiceUrl = process.env.OLYMPUS_LSP_URL || ""
|
||||||
constructor(serviceUrl: string) {
|
const voltageServiceUrl = process.env.VOLTAGE_LSP_URL || ""
|
||||||
this.serviceUrl = serviceUrl
|
const channelThreshold = EnvCanBeInteger("LSP_CHANNEL_THRESHOLD")
|
||||||
|
const maxRelativeFee = EnvCanBeInteger("LSP_MAX_FEE_BPS") / 10000
|
||||||
|
return { olympusServiceUrl, voltageServiceUrl, channelThreshold, maxRelativeFee }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type OlympusOrder = {
|
||||||
|
"lsp_balance_sat": string,
|
||||||
|
"client_balance_sat": string,
|
||||||
|
"required_channel_confirmations": number,
|
||||||
|
"funding_confirms_within_blocks": number,
|
||||||
|
"channel_expiry_blocks": number,
|
||||||
|
"refund_onchain_address": string,
|
||||||
|
"announce_channel": boolean,
|
||||||
|
"public_key": string
|
||||||
|
}
|
||||||
|
|
||||||
|
class LSP {
|
||||||
|
settings: LSPSettings
|
||||||
|
liquidityProvider: LiquidityProvider
|
||||||
|
lnd: LND
|
||||||
|
log: PubLogger
|
||||||
|
constructor(serviceName: string, settings: LSPSettings, lnd: LND, liquidityProvider: LiquidityProvider) {
|
||||||
|
this.settings = settings
|
||||||
|
this.lnd = lnd
|
||||||
|
this.liquidityProvider = liquidityProvider
|
||||||
|
this.log = getLogger({ component: serviceName })
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldOpenChannel = async (): Promise<{ shouldOpen: false } | { shouldOpen: true, maxSpendable: number }> => {
|
||||||
|
if (this.settings.channelThreshold === 0) {
|
||||||
|
this.log("channel threshold is 0")
|
||||||
|
return { shouldOpen: false }
|
||||||
|
}
|
||||||
|
const channels = await this.lnd.ListChannels()
|
||||||
|
if (channels.channels.length > 0) {
|
||||||
|
this.log("this node already has open channels")
|
||||||
|
return { shouldOpen: false }
|
||||||
|
}
|
||||||
|
const pendingChannels = await this.lnd.ListPendingChannels()
|
||||||
|
if (pendingChannels.pendingOpenChannels.length > 0) {
|
||||||
|
this.log("this node already has pending channels")
|
||||||
|
return { shouldOpen: false }
|
||||||
|
}
|
||||||
|
const userState = await this.liquidityProvider.CheckUserState()
|
||||||
|
if (!userState || userState.max_withdrawable < this.settings.channelThreshold) {
|
||||||
|
this.log("user balance too low to trigger channel request")
|
||||||
|
return { shouldOpen: false }
|
||||||
|
}
|
||||||
|
return { shouldOpen: true, maxSpendable: userState.max_withdrawable }
|
||||||
|
}
|
||||||
|
|
||||||
|
addPeer = async (pubKey: string, host: string) => {
|
||||||
|
const { peers } = await this.lnd.ListPeers()
|
||||||
|
if (!peers.find(p => p.pubKey === pubKey)) {
|
||||||
|
await this.lnd.ConnectPeer({ host, pubkey: pubKey })
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OlympusLSP extends LSP {
|
||||||
|
constructor(settings: LSPSettings, lnd: LND, liquidityProvider: LiquidityProvider) {
|
||||||
|
super("OlympusLSP", settings, lnd, liquidityProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
openChannelIfReady = async (): Promise<boolean> => {
|
||||||
|
this.log("checking if channel should be opened")
|
||||||
|
const shouldOpen = await this.shouldOpenChannel()
|
||||||
|
if (!shouldOpen.shouldOpen) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!this.settings.olympusServiceUrl) {
|
||||||
|
this.log("no olympus service url provided")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const serviceInfo = await this.getInfo()
|
||||||
|
if (+serviceInfo.options.min_initial_lsp_balance_sat > shouldOpen.maxSpendable) {
|
||||||
|
this.log("user balance too low for service minimum")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const [servicePub, host] = serviceInfo.uris[0].split('@')
|
||||||
|
await this.addPeer(servicePub, host)
|
||||||
|
const lndInfo = await this.lnd.GetInfo()
|
||||||
|
const myPub = lndInfo.identityPubkey
|
||||||
|
const refundAddr = await this.lnd.NewAddress(AddressType.WITNESS_PUBKEY_HASH)
|
||||||
|
const lspBalance = (this.settings.channelThreshold * 2).toString()
|
||||||
|
const order = await this.createOrder({ pubKey: myPub, refundAddr: refundAddr.address, lspBalance, clientBalance: "0" })
|
||||||
|
if (order.payment.state !== 'EXPECT_PAYMENT') {
|
||||||
|
this.log("order not in expect payment state")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const decoded = await this.lnd.DecodeInvoice(order.payment.bolt11_invoice)
|
||||||
|
if (decoded.numSatoshis !== +order.payment.order_total_sat) {
|
||||||
|
this.log("invoice amount does not match order total")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (decoded.numSatoshis > shouldOpen.maxSpendable) {
|
||||||
|
this.log("invoice amount exceeds user balance")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const relativeFee = +order.payment.fee_total_sat / this.settings.channelThreshold
|
||||||
|
if (relativeFee > this.settings.maxRelativeFee) {
|
||||||
|
this.log("invoice fee exceeds max fee percent")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
await this.liquidityProvider.PayInvoice(order.payment.bolt11_invoice)
|
||||||
|
this.log("paid invoice to open channel")
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
getInfo = async () => {
|
getInfo = async () => {
|
||||||
const res = await fetch(`${this.serviceUrl}/getinfo`)
|
const res = await fetch(`${this.settings.olympusServiceUrl}/getinfo`)
|
||||||
const json = await res.json() as { options: {}, uris: string[] }
|
const json = await res.json() as { options: { min_initial_lsp_balance_sat: string }, uris: string[] }
|
||||||
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrder = async (req: { public_key: string }) => {
|
createOrder = async (orderInfo: { pubKey: string, refundAddr: string, lspBalance: string, clientBalance: string }) => {
|
||||||
const res = await fetch(`${this.serviceUrl}/create_order`, {
|
const req: OlympusOrder = {
|
||||||
|
public_key: orderInfo.pubKey,
|
||||||
|
announce_channel: true,
|
||||||
|
refund_onchain_address: orderInfo.refundAddr,
|
||||||
|
lsp_balance_sat: orderInfo.lspBalance,
|
||||||
|
client_balance_sat: orderInfo.clientBalance,
|
||||||
|
channel_expiry_blocks: 144,
|
||||||
|
funding_confirms_within_blocks: 6,
|
||||||
|
required_channel_confirmations: 0
|
||||||
|
}
|
||||||
|
const res = await fetch(`${this.settings.olympusServiceUrl}/create_order`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(req),
|
body: JSON.stringify(req),
|
||||||
headers: { "Content-Type": "application/json" }
|
headers: { "Content-Type": "application/json" }
|
||||||
})
|
})
|
||||||
const json = await res.json() as {}
|
const json = await res.json() as { order_id: string, payment: { state: 'EXPECT_PAYMENT', bolt11_invoice: string, fee_total_sat: string, order_total_sat: string } }
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrder = async (orderId: string) => {
|
getOrder = async (orderId: string) => {
|
||||||
const res = await fetch(`${this.serviceUrl}/get_order&order_id=${orderId}`)
|
const res = await fetch(`${this.settings.olympusServiceUrl}/get_order&order_id=${orderId}`)
|
||||||
const json = await res.json() as {}
|
const json = await res.json() as {}
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class VoltageLSP extends LSP {
|
||||||
|
constructor(settings: LSPSettings, lnd: LND, liquidityProvider: LiquidityProvider) {
|
||||||
|
super("VoltageLSP", settings, lnd, liquidityProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
getInfo = async () => {
|
||||||
|
const res = await fetch(`${this.settings.voltageServiceUrl}/info`)
|
||||||
|
const json = await res.json() as { connection_methods: { address: string, port: string, type: string }[], pubkey: string }
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
getFees = async (amtMsat: string, pubkey: string) => {
|
||||||
|
const res = await fetch(`${this.settings.voltageServiceUrl}/fee`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ amount_msat: amtMsat, pubkey }),
|
||||||
|
headers: { "Content-Type": "application/json" }
|
||||||
|
})
|
||||||
|
const json = await res.json() as { fee_amount_msat: number, id: string }
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
openChannelIfReady = async (): Promise<boolean> => {
|
||||||
|
const shouldOpen = await this.shouldOpenChannel()
|
||||||
|
if (!shouldOpen.shouldOpen) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.settings.voltageServiceUrl) {
|
||||||
|
this.log("no voltage service url provided")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const lndInfo = await this.lnd.GetInfo()
|
||||||
|
const myPub = lndInfo.identityPubkey
|
||||||
|
const amtMsats = this.settings.channelThreshold.toString() + "000"
|
||||||
|
const fee = await this.getFees(amtMsats, myPub)
|
||||||
|
const feeSats = fee.fee_amount_msat / 1000
|
||||||
|
const relativeFee = feeSats / this.settings.channelThreshold
|
||||||
|
|
||||||
|
if (relativeFee > this.settings.maxRelativeFee) {
|
||||||
|
this.log("fee percent exceeds max fee percent")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const info = await this.getInfo()
|
||||||
|
const ipv4 = info.connection_methods.find(c => c.type === 'ipv4')
|
||||||
|
if (!ipv4) {
|
||||||
|
this.log("no ipv4 address found")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
await this.addPeer(info.pubkey, `${ipv4.address}:${ipv4.port}`)
|
||||||
|
|
||||||
|
const invoice = await this.lnd.NewInvoice(this.settings.channelThreshold, "open channel", 60 * 60)
|
||||||
|
const res = await this.proposal(invoice.payRequest, fee.id)
|
||||||
|
const decoded = await this.lnd.DecodeInvoice(res.jit_bolt11)
|
||||||
|
if (decoded.numSatoshis !== this.settings.channelThreshold + feeSats) {
|
||||||
|
this.log("invoice amount does not math requested amount")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.liquidityProvider.PayInvoice(res.jit_bolt11)
|
||||||
|
this.log("paid invoice to open channel")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
proposal = async (bolt11: string, feeId: string) => {
|
||||||
|
const res = await fetch(`${this.settings.voltageServiceUrl}/proposal`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ bolt11, fee_id: feeId }),
|
||||||
|
headers: { "Content-Type": "application/json" }
|
||||||
|
})
|
||||||
|
const json = await res.json() as { jit_bolt11: string }
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { HtlcEvent } from "../../../proto/lnd/router"
|
import { HtlcEvent } from "../../../proto/lnd/router"
|
||||||
|
import { LiquiditySettings } from "./liquidityManager"
|
||||||
export type NodeSettings = {
|
export type NodeSettings = {
|
||||||
lndAddr: string
|
lndAddr: string
|
||||||
lndCertPath: string
|
lndCertPath: string
|
||||||
|
|
@ -9,11 +10,11 @@ export type LndSettings = {
|
||||||
feeRateLimit: number
|
feeRateLimit: number
|
||||||
feeFixedLimit: number
|
feeFixedLimit: number
|
||||||
mockLnd: boolean
|
mockLnd: boolean
|
||||||
liquidityProviderPub: string
|
|
||||||
useOnlyLiquidityProvider: boolean
|
|
||||||
|
|
||||||
otherNode?: NodeSettings
|
otherNode?: NodeSettings
|
||||||
thirdNode?: NodeSettings
|
thirdNode?: NodeSettings
|
||||||
|
|
||||||
|
liquiditySettings: LiquiditySettings
|
||||||
}
|
}
|
||||||
type TxOutput = {
|
type TxOutput = {
|
||||||
hash: string
|
hash: string
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { NostrSend } from '../nostr/handler.js'
|
||||||
import MetricsManager from '../metrics/index.js'
|
import MetricsManager from '../metrics/index.js'
|
||||||
import { LoggedEvent } from '../storage/eventsLog.js'
|
import { LoggedEvent } from '../storage/eventsLog.js'
|
||||||
import { LiquidityProvider } from "../lnd/liquidityProvider.js"
|
import { LiquidityProvider } from "../lnd/liquidityProvider.js"
|
||||||
|
import { LiquidityManager } from "../lnd/liquidityManager.js"
|
||||||
|
|
||||||
type UserOperationsSub = {
|
type UserOperationsSub = {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -37,20 +38,22 @@ export default class {
|
||||||
paymentSubs: Record<string, ((op: Types.UserOperation) => void) | null> = {}
|
paymentSubs: Record<string, ((op: Types.UserOperation) => void) | null> = {}
|
||||||
metricsManager: MetricsManager
|
metricsManager: MetricsManager
|
||||||
liquidProvider: LiquidityProvider
|
liquidProvider: LiquidityProvider
|
||||||
|
liquidityManager: LiquidityManager
|
||||||
nostrSend: NostrSend = () => { getLogger({})("nostr send not initialized yet") }
|
nostrSend: NostrSend = () => { getLogger({})("nostr send not initialized yet") }
|
||||||
constructor(settings: MainSettings, storage: Storage) {
|
constructor(settings: MainSettings, storage: Storage) {
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
this.liquidProvider = new LiquidityProvider(settings.lndSettings.liquidityProviderPub, this.invoicePaidCb)
|
this.liquidProvider = new LiquidityProvider(settings.lndSettings.liquiditySettings.liquidityProviderPub, this.invoicePaidCb)
|
||||||
this.lnd = new LND(settings.lndSettings, this.liquidProvider, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb)
|
this.lnd = new LND(settings.lndSettings, this.liquidProvider, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb)
|
||||||
|
this.liquidityManager = new LiquidityManager(this.settings.lndSettings.liquiditySettings, this.liquidProvider, this.lnd)
|
||||||
this.metricsManager = new MetricsManager(this.storage, this.lnd)
|
this.metricsManager = new MetricsManager(this.storage, this.lnd)
|
||||||
|
|
||||||
this.paymentManager = new PaymentManager(this.storage, this.lnd, this.settings, this.addressPaidCb, this.invoicePaidCb)
|
this.paymentManager = new PaymentManager(this.storage, this.lnd, this.settings, this.addressPaidCb, this.invoicePaidCb)
|
||||||
this.productManager = new ProductManager(this.storage, this.paymentManager, this.settings)
|
this.productManager = new ProductManager(this.storage, this.paymentManager, this.settings)
|
||||||
this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager)
|
this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager)
|
||||||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stop() {
|
Stop() {
|
||||||
this.lnd.Stop()
|
this.lnd.Stop()
|
||||||
this.applicationManager.Stop()
|
this.applicationManager.Stop()
|
||||||
|
|
@ -187,6 +190,7 @@ export default class {
|
||||||
this.sendOperationToNostr(userInvoice.linkedApplication, userInvoice.user.user_id, op)
|
this.sendOperationToNostr(userInvoice.linkedApplication, userInvoice.user.user_id, op)
|
||||||
this.createZapReceipt(log, userInvoice)
|
this.createZapReceipt(log, userInvoice)
|
||||||
log("paid invoice processed successfully")
|
log("paid invoice processed successfully")
|
||||||
|
this.liquidityManager.afterInInvoicePaid()
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
log(ERROR, "cannot process paid invoice", err.message || "")
|
log(ERROR, "cannot process paid invoice", err.message || "")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,10 @@ export const LoadTestSettingsFromEnv = (): TestSettings => {
|
||||||
lndCertPath: EnvMustBeNonEmptyString("LND_FOURTH_CERT_PATH"),
|
lndCertPath: EnvMustBeNonEmptyString("LND_FOURTH_CERT_PATH"),
|
||||||
lndMacaroonPath: EnvMustBeNonEmptyString("LND_FOURTH_MACAROON_PATH")
|
lndMacaroonPath: EnvMustBeNonEmptyString("LND_FOURTH_MACAROON_PATH")
|
||||||
},
|
},
|
||||||
liquidityProviderPub: ""
|
liquiditySettings: {
|
||||||
|
...settings.lndSettings.liquiditySettings,
|
||||||
|
liquidityProviderPub: "",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
skipSanityCheck: true,
|
skipSanityCheck: true,
|
||||||
bitcoinCoreSettings: {
|
bitcoinCoreSettings: {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import * as Types from '../../proto/autogenerated/ts/types.js'
|
||||||
|
|
||||||
export const initBootstrappedInstance = async (T: TestBase) => {
|
export const initBootstrappedInstance = async (T: TestBase) => {
|
||||||
const settings = LoadTestSettingsFromEnv()
|
const settings = LoadTestSettingsFromEnv()
|
||||||
settings.lndSettings.useOnlyLiquidityProvider = true
|
settings.lndSettings.liquiditySettings.useOnlyLiquidityProvider = true
|
||||||
settings.lndSettings.liquidityProviderPub = T.app.publicKey
|
settings.lndSettings.liquiditySettings.liquidityProviderPub = T.app.publicKey
|
||||||
settings.lndSettings.mainNode = settings.lndSettings.thirdNode
|
settings.lndSettings.mainNode = settings.lndSettings.thirdNode
|
||||||
const initialized = await initMainHandler(getLogger({ component: "bootstrapped" }), settings)
|
const initialized = await initMainHandler(getLogger({ component: "bootstrapped" }), settings)
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue