open more channels
This commit is contained in:
parent
20d2afa464
commit
e7c2511fc8
4 changed files with 67 additions and 64 deletions
|
|
@ -290,7 +290,7 @@ export default class {
|
|||
throw new Error("lnd node is currently out of sync")
|
||||
}
|
||||
await this.Health()
|
||||
this.log("paying invoice", invoice, "for", amount, "sats")
|
||||
this.log("paying invoice", invoice, "for", amount, "sats with", useProvider ? 'provider' : 'lnd')
|
||||
if (useProvider) {
|
||||
const res = await this.liquidProvider.PayInvoice(invoice)
|
||||
const providerDst = this.liquidProvider.GetProviderDestination()
|
||||
|
|
@ -314,6 +314,9 @@ export default class {
|
|||
case Payment_PaymentStatus.SUCCEEDED:
|
||||
this.log("invoice payment succeded", Number(payment.valueSat))
|
||||
res({ feeSat: Math.ceil(Number(payment.feeMsat) / 1000), valueSat: Number(payment.valueSat), paymentPreimage: payment.paymentPreimage })
|
||||
return
|
||||
default:
|
||||
this.log("inflight payment update index", Number(payment.paymentIndex), Payment_PaymentStatus[payment.status])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -61,29 +61,6 @@ class LSP {
|
|||
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("balance of", userState?.max_withdrawable || 0, "is lower than channel threshold of", this.settings.channelThreshold)
|
||||
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)) {
|
||||
|
|
@ -98,18 +75,14 @@ export class FlashsatsLSP extends LSP {
|
|||
super("FlashsatsLSP", settings, lnd, liquidityProvider)
|
||||
}
|
||||
|
||||
openChannelIfReady = async (): Promise<OrderResponse | null> => {
|
||||
const shouldOpen = await this.shouldOpenChannel()
|
||||
if (!shouldOpen.shouldOpen) {
|
||||
return null
|
||||
}
|
||||
requestChannel = async (maxSpendable: number): Promise<OrderResponse | null> => {
|
||||
if (!this.settings.flashsatsServiceUrl) {
|
||||
this.log("no flashsats service url provided")
|
||||
return null
|
||||
}
|
||||
const serviceInfo = await this.getInfo()
|
||||
if (+serviceInfo.options.min_initial_client_balance_sat > shouldOpen.maxSpendable) {
|
||||
this.log("balance of", shouldOpen.maxSpendable, "is lower than service minimum of", serviceInfo.options.min_initial_client_balance_sat)
|
||||
if (+serviceInfo.options.min_initial_client_balance_sat > maxSpendable) {
|
||||
this.log("balance of", maxSpendable, "is lower than service minimum of", serviceInfo.options.min_initial_client_balance_sat)
|
||||
return null
|
||||
}
|
||||
const lndInfo = await this.lnd.GetInfo()
|
||||
|
|
@ -118,7 +91,8 @@ export class FlashsatsLSP extends LSP {
|
|||
this.log("no uri found for this node,uri is required to use flashsats")
|
||||
return null
|
||||
}
|
||||
const lspBalance = (this.settings.channelThreshold * 2).toString()
|
||||
const channelSize = Math.floor(maxSpendable * (1 - this.settings.maxRelativeFee)) * 2
|
||||
const lspBalance = channelSize.toString()
|
||||
const chanExpiryBlocks = serviceInfo.options.max_channel_expiry_blocks
|
||||
const order = await this.createOrder({ nodeUri: myUri, lspBalance, clientBalance: "0", chanExpiryBlocks })
|
||||
if (order.payment.state !== 'EXPECT_PAYMENT') {
|
||||
|
|
@ -130,11 +104,11 @@ export class FlashsatsLSP extends LSP {
|
|||
this.log("invoice of amount", decoded.numSatoshis, "does not match order total of", order.payment.order_total_sat)
|
||||
return null
|
||||
}
|
||||
if (decoded.numSatoshis > shouldOpen.maxSpendable) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", shouldOpen.maxSpendable)
|
||||
if (decoded.numSatoshis > maxSpendable) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", maxSpendable)
|
||||
return null
|
||||
}
|
||||
const relativeFee = +order.payment.fee_total_sat / this.settings.channelThreshold
|
||||
const relativeFee = +order.payment.fee_total_sat / channelSize
|
||||
if (relativeFee > this.settings.maxRelativeFee) {
|
||||
this.log("invoice relative fee of", relativeFee, "exceeds max relative fee of", this.settings.maxRelativeFee)
|
||||
return null
|
||||
|
|
@ -175,18 +149,14 @@ export class OlympusLSP extends LSP {
|
|||
super("OlympusLSP", settings, lnd, liquidityProvider)
|
||||
}
|
||||
|
||||
openChannelIfReady = async (): Promise<OrderResponse | null> => {
|
||||
const shouldOpen = await this.shouldOpenChannel()
|
||||
if (!shouldOpen.shouldOpen) {
|
||||
return null
|
||||
}
|
||||
requestChannel = async (maxSpendable: number): Promise<OrderResponse | null> => {
|
||||
if (!this.settings.olympusServiceUrl) {
|
||||
this.log("no olympus service url provided")
|
||||
return null
|
||||
}
|
||||
const serviceInfo = await this.getInfo()
|
||||
if (+serviceInfo.min_initial_client_balance_sat > shouldOpen.maxSpendable) {
|
||||
this.log("balance of", shouldOpen.maxSpendable, "is lower than service minimum of", serviceInfo.min_initial_client_balance_sat)
|
||||
if (+serviceInfo.min_initial_client_balance_sat > maxSpendable) {
|
||||
this.log("balance of", maxSpendable, "is lower than service minimum of", serviceInfo.min_initial_client_balance_sat)
|
||||
return null
|
||||
}
|
||||
const [servicePub, host] = serviceInfo.uris[0].split('@')
|
||||
|
|
@ -194,7 +164,8 @@ export class OlympusLSP extends LSP {
|
|||
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 channelSize = Math.floor(maxSpendable * (1 - this.settings.maxRelativeFee)) * 2
|
||||
const lspBalance = channelSize.toString()
|
||||
const chanExpiryBlocks = serviceInfo.max_channel_expiry_blocks
|
||||
const order = await this.createOrder({ pubKey: myPub, refundAddr: refundAddr.address, lspBalance, clientBalance: "0", chanExpiryBlocks })
|
||||
if (order.payment.bolt11.state !== 'EXPECT_PAYMENT') {
|
||||
|
|
@ -206,11 +177,11 @@ export class OlympusLSP extends LSP {
|
|||
this.log("invoice of amount", decoded.numSatoshis, "does not match order total of", order.payment.bolt11.order_total_sat)
|
||||
return null
|
||||
}
|
||||
if (decoded.numSatoshis > shouldOpen.maxSpendable) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", shouldOpen.maxSpendable)
|
||||
if (decoded.numSatoshis > maxSpendable) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", maxSpendable)
|
||||
return null
|
||||
}
|
||||
const relativeFee = +order.payment.bolt11.fee_total_sat / this.settings.channelThreshold
|
||||
const relativeFee = +order.payment.bolt11.fee_total_sat / channelSize
|
||||
if (relativeFee > this.settings.maxRelativeFee) {
|
||||
this.log("invoice relative fee of", relativeFee, "exceeds max relative fee of", this.settings.maxRelativeFee)
|
||||
return null
|
||||
|
|
@ -277,12 +248,7 @@ export class VoltageLSP extends LSP {
|
|||
return json
|
||||
}
|
||||
|
||||
openChannelIfReady = async (): Promise<OrderResponse | null> => {
|
||||
const shouldOpen = await this.shouldOpenChannel()
|
||||
if (!shouldOpen.shouldOpen) {
|
||||
return null
|
||||
}
|
||||
|
||||
requestChannel = async (maxSpendable: number): Promise<OrderResponse | null> => {
|
||||
if (!this.settings.voltageServiceUrl) {
|
||||
this.log("no voltage service url provided")
|
||||
return null
|
||||
|
|
@ -290,10 +256,11 @@ export class VoltageLSP extends LSP {
|
|||
|
||||
const lndInfo = await this.lnd.GetInfo()
|
||||
const myPub = lndInfo.identityPubkey
|
||||
const amtMsats = this.settings.channelThreshold * 1000
|
||||
const amtSats = Math.floor(maxSpendable * 0.9)
|
||||
const amtMsats = Math.floor(maxSpendable * 0.9) * 1000
|
||||
const fee = await this.getFees(amtMsats, myPub)
|
||||
const feeSats = fee.fee_amount_msat / 1000
|
||||
const relativeFee = feeSats / this.settings.channelThreshold
|
||||
const relativeFee = feeSats / (amtSats * 1.1)
|
||||
|
||||
if (relativeFee > this.settings.maxRelativeFee) {
|
||||
this.log("relative fee of", relativeFee, "exceeds max relative fee of", this.settings.maxRelativeFee)
|
||||
|
|
@ -308,15 +275,18 @@ export class VoltageLSP extends LSP {
|
|||
}
|
||||
await this.addPeer(info.pubkey, `${ipv4.address}:${ipv4.port}`)
|
||||
|
||||
const invoice = await this.lnd.NewInvoice(this.settings.channelThreshold, "open channel", 60 * 60)
|
||||
const invoice = await this.lnd.NewInvoice(amtSats, "open channel", 60 * 60)
|
||||
const proposalRes = await this.proposal(invoice.payRequest, fee.id)
|
||||
this.log("proposal res", proposalRes, fee.id)
|
||||
const decoded = await this.lnd.DecodeInvoice(proposalRes.jit_bolt11)
|
||||
if (decoded.numSatoshis !== this.settings.channelThreshold + feeSats) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "does not match expected amount of", this.settings.channelThreshold + feeSats)
|
||||
if (decoded.numSatoshis !== amtSats + feeSats) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "does not match expected amount of", amtSats + feeSats)
|
||||
return null
|
||||
}
|
||||
if (decoded.numSatoshis > maxSpendable) {
|
||||
this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", maxSpendable)
|
||||
return null
|
||||
}
|
||||
|
||||
const res = await this.liquidityProvider.PayInvoice(proposalRes.jit_bolt11)
|
||||
const fees = feeSats + res.network_fee + res.service_fee
|
||||
this.log("paid", res.amount_paid, "to open channel, and a fee of", fees)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { SendPaymentRequest } from "../../../proto/lnd/router";
|
|||
export const PayInvoiceReq = (invoice: string, amount: number, feeLimit: number): SendPaymentRequest => ({
|
||||
amt: BigInt(amount),
|
||||
feeLimitSat: BigInt(feeLimit),
|
||||
noInflightUpdates: true,
|
||||
noInflightUpdates: false,
|
||||
paymentRequest: invoice,
|
||||
maxParts: 3,
|
||||
timeoutSeconds: 50,
|
||||
|
|
@ -25,6 +25,5 @@ export const PayInvoiceReq = (invoice: string, amount: number, feeLimit: number)
|
|||
paymentHash: Buffer.alloc(0),
|
||||
routeHints: [],
|
||||
timePref: 0,
|
||||
|
||||
outgoingChanId: '0'
|
||||
})
|
||||
|
|
@ -71,6 +71,7 @@ export class LiquidityManager {
|
|||
this.log("channel does not have enough balance for invoice,suggesting provider")
|
||||
return 'provider'
|
||||
}
|
||||
|
||||
afterInInvoicePaid = async () => {
|
||||
try {
|
||||
await this.orderChannelIfNeeded()
|
||||
|
|
@ -78,9 +79,39 @@ export class LiquidityManager {
|
|||
this.log("error ordering channel", e)
|
||||
}
|
||||
}
|
||||
|
||||
shouldOpenChannel = async (): Promise<{ shouldOpen: false } | { shouldOpen: true, maxSpendable: number }> => {
|
||||
const threshold = this.settings.lspSettings.channelThreshold
|
||||
if (threshold === 0) {
|
||||
this.log("channel threshold is 0")
|
||||
return { shouldOpen: false }
|
||||
}
|
||||
const { remote } = await this.lnd.ChannelBalance()
|
||||
if (remote > threshold) {
|
||||
this.log("remote channel balance is already more than threshold")
|
||||
return { shouldOpen: false }
|
||||
}
|
||||
const pendingChannels = await this.lnd.ListPendingChannels()
|
||||
if (pendingChannels.pendingOpenChannels.length > 0) {
|
||||
this.log("pending open channels detected, liquidiity might be on the way")
|
||||
return { shouldOpen: false }
|
||||
}
|
||||
const userState = await this.liquidityProvider.CheckUserState()
|
||||
if (!userState || userState.max_withdrawable < threshold) {
|
||||
this.log("balance of", userState?.max_withdrawable || 0, "is lower than channel threshold of", threshold)
|
||||
return { shouldOpen: false }
|
||||
}
|
||||
return { shouldOpen: true, maxSpendable: userState.max_withdrawable }
|
||||
}
|
||||
|
||||
orderChannelIfNeeded = async () => {
|
||||
const existingOrder = await this.storage.liquidityStorage.GetLatestLspOrder()
|
||||
if (existingOrder) {
|
||||
if (existingOrder && existingOrder.created_at > new Date(Date.now() - 20 * 60 * 1000)) {
|
||||
this.log("most recent lsp order is less than 20 minutes old")
|
||||
return
|
||||
}
|
||||
const shouldOpen = await this.shouldOpenChannel()
|
||||
if (!shouldOpen.shouldOpen) {
|
||||
return
|
||||
}
|
||||
if (this.channelRequested || this.channelRequesting) {
|
||||
|
|
@ -88,7 +119,7 @@ export class LiquidityManager {
|
|||
}
|
||||
this.channelRequesting = true
|
||||
this.log("checking if channel should be requested")
|
||||
const olympusOk = await this.olympusLSP.openChannelIfReady()
|
||||
const olympusOk = await this.olympusLSP.requestChannel(shouldOpen.maxSpendable)
|
||||
if (olympusOk) {
|
||||
this.log("requested channel from olympus")
|
||||
this.channelRequested = true
|
||||
|
|
@ -97,7 +128,7 @@ export class LiquidityManager {
|
|||
await this.storage.liquidityStorage.SaveLspOrder({ service_name: 'olympus', invoice: olympusOk.invoice, total_paid: olympusOk.totalSats, order_id: olympusOk.orderId, fees: olympusOk.fees })
|
||||
return
|
||||
}
|
||||
const voltageOk = await this.voltageLSP.openChannelIfReady()
|
||||
const voltageOk = await this.voltageLSP.requestChannel(shouldOpen.maxSpendable)
|
||||
if (voltageOk) {
|
||||
this.log("requested channel from voltage")
|
||||
this.channelRequested = true
|
||||
|
|
@ -107,7 +138,7 @@ export class LiquidityManager {
|
|||
return
|
||||
}
|
||||
|
||||
const flashsatsOk = await this.flashsatsLSP.openChannelIfReady()
|
||||
const flashsatsOk = await this.flashsatsLSP.requestChannel(shouldOpen.maxSpendable)
|
||||
if (flashsatsOk) {
|
||||
this.log("requested channel from flashsats")
|
||||
this.channelRequested = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue