more bypassing

This commit is contained in:
shocknet-justin 2025-12-12 16:00:52 -05:00
parent aed90ae929
commit 7728073653
8 changed files with 106 additions and 6 deletions

22
package-lock.json generated
View file

@ -33,6 +33,7 @@
"globby": "^13.1.2", "globby": "^13.1.2",
"grpc-tools": "^1.12.4", "grpc-tools": "^1.12.4",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"light-bolt11-decoder": "^3.2.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"nostr-tools": "^2.13.0", "nostr-tools": "^2.13.0",
"pg": "^8.4.0", "pg": "^8.4.0",
@ -4333,6 +4334,27 @@
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
}, },
"node_modules/light-bolt11-decoder": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-3.2.0.tgz",
"integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==",
"license": "MIT",
"dependencies": {
"@scure/base": "1.1.1"
}
},
"node_modules/light-bolt11-decoder/node_modules/@scure/base": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
"integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"license": "MIT"
},
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",

View file

@ -51,6 +51,7 @@
"globby": "^13.1.2", "globby": "^13.1.2",
"grpc-tools": "^1.12.4", "grpc-tools": "^1.12.4",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"light-bolt11-decoder": "^3.2.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"nostr-tools": "^2.13.0", "nostr-tools": "^2.13.0",
"pg": "^8.4.0", "pg": "^8.4.0",

View file

@ -3,6 +3,7 @@ import crypto from 'crypto'
import { credentials, Metadata } from '@grpc/grpc-js' import { credentials, Metadata } from '@grpc/grpc-js'
import { GrpcTransport } from "@protobuf-ts/grpc-transport"; import { GrpcTransport } from "@protobuf-ts/grpc-transport";
import fs from 'fs' import fs from 'fs'
import { decode as decodeBolt11 } from 'light-bolt11-decoder'
import * as Types from '../../../proto/autogenerated/ts/types.js' import * as Types from '../../../proto/autogenerated/ts/types.js'
import { LightningClient } from '../../../proto/lnd/lightning.client.js' import { LightningClient } from '../../../proto/lnd/lightning.client.js'
import { InvoicesClient } from '../../../proto/lnd/invoices.client.js' import { InvoicesClient } from '../../../proto/lnd/invoices.client.js'
@ -170,6 +171,9 @@ export default class {
return res.response return res.response
} }
async ListPendingChannels(): Promise<PendingChannelsResponse> { async ListPendingChannels(): Promise<PendingChannelsResponse> {
if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) {
return { pendingOpenChannels: [], pendingClosingChannels: [], pendingForceClosingChannels: [], waitingCloseChannels: [], totalLimboBalance: 0n }
}
// console.log("Listing pending channels") // console.log("Listing pending channels")
const res = await this.lightning.pendingChannels({ includeRawTx: false }, DeadLineMetadata()) const res = await this.lightning.pendingChannels({ includeRawTx: false }, DeadLineMetadata())
return res.response return res.response
@ -195,6 +199,10 @@ export default class {
} }
async Health(): Promise<void> { async Health(): Promise<void> {
// Skip health check when bypass is enabled
if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) {
return
}
// console.log("Checking health") // console.log("Checking health")
if (!this.ready) { if (!this.ready) {
throw new Error("not ready") throw new Error("not ready")
@ -324,6 +332,10 @@ export default class {
} }
async NewAddress(addressType: Types.AddressType, { useProvider, from }: TxActionOptions): Promise<NewAddressResponse> { async NewAddress(addressType: Types.AddressType, { useProvider, from }: TxActionOptions): Promise<NewAddressResponse> {
// 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") // console.log("Creating new address")
let lndAddressType: AddressType let lndAddressType: AddressType
switch (addressType) { switch (addressType) {
@ -355,7 +367,9 @@ export default class {
async NewInvoice(value: number, memo: string, expiry: number, { useProvider, from }: TxActionOptions, blind = false): Promise<Invoice> { async NewInvoice(value: number, memo: string, expiry: number, { useProvider, from }: TxActionOptions, blind = false): Promise<Invoice> {
// console.log("Creating new invoice") // console.log("Creating new invoice")
if (useProvider) { // Force use of provider when bypass is enabled
const mustUseProvider = this.liquidProvider.getSettings().useOnlyLiquidityProvider || useProvider
if (mustUseProvider) {
console.log("using provider") console.log("using provider")
const invoice = await this.liquidProvider.AddInvoice(value, memo, from, expiry) const invoice = await this.liquidProvider.AddInvoice(value, memo, from, expiry)
const providerDst = this.liquidProvider.GetProviderDestination() const providerDst = this.liquidProvider.GetProviderDestination()
@ -372,6 +386,23 @@ export default class {
} }
async DecodeInvoice(paymentRequest: string): Promise<DecodedInvoice> { async DecodeInvoice(paymentRequest: string): Promise<DecodedInvoice> {
if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) {
// Use light-bolt11-decoder when LND is bypassed
const decoded = decodeBolt11(paymentRequest)
let numSatoshis = 0
let paymentHash = ''
for (const section of decoded.sections) {
if (section.name === 'amount') {
// Amount is in millisatoshis
numSatoshis = Math.floor(Number(section.value) / 1000)
} else if (section.name === 'payment_hash') {
paymentHash = section.value as string
}
}
return { numSatoshis, paymentHash }
}
// console.log("Decoding invoice") // console.log("Decoding invoice")
const res = await this.lightning.decodePayReq({ payReq: paymentRequest }, DeadLineMetadata()) const res = await this.lightning.decodePayReq({ payReq: paymentRequest }, DeadLineMetadata())
return { numSatoshis: Number(res.response.numSatoshis), paymentHash: res.response.paymentHash } return { numSatoshis: Number(res.response.numSatoshis), paymentHash: res.response.paymentHash }
@ -400,7 +431,9 @@ export default class {
this.log("outgoing ops locked, rejecting payment request") this.log("outgoing ops locked, rejecting payment request")
throw new Error("lnd node is currently out of sync") throw new Error("lnd node is currently out of sync")
} }
if (useProvider) { // Force use of provider when bypass is enabled
const mustUseProvider = this.liquidProvider.getSettings().useOnlyLiquidityProvider || useProvider
if (mustUseProvider) {
const res = await this.liquidProvider.PayInvoice(invoice, decodedAmount, from) const res = await this.liquidProvider.PayInvoice(invoice, decodedAmount, from)
const providerDst = this.liquidProvider.GetProviderDestination() const providerDst = this.liquidProvider.GetProviderDestination()
return { feeSat: res.network_fee + res.service_fee, valueSat: res.amount_paid, paymentPreimage: res.preimage, providerDst } return { feeSat: res.network_fee + res.service_fee, valueSat: res.amount_paid, paymentPreimage: res.preimage, providerDst }
@ -455,6 +488,10 @@ export default class {
} }
async PayAddress(address: string, amount: number, satPerVByte: number, label = "", { useProvider, from }: TxActionOptions): Promise<SendCoinsResponse> { async PayAddress(address: string, amount: number, satPerVByte: number, label = "", { useProvider, from }: TxActionOptions): Promise<SendCoinsResponse> {
// 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") // console.log("Paying address")
if (this.outgoingOpsLocked) { if (this.outgoingOpsLocked) {
this.log("outgoing ops locked, rejecting payment request") this.log("outgoing ops locked, rejecting payment request")
@ -551,6 +588,9 @@ export default class {
} }
async GetForwardingHistory(indexOffset: number, startTime = 0, endTime = 0): Promise<ForwardingHistoryResponse> { async GetForwardingHistory(indexOffset: number, startTime = 0, endTime = 0): Promise<ForwardingHistoryResponse> {
if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) {
return { forwardingEvents: [], lastOffsetIndex: indexOffset }
}
// console.log("Getting forwarding history") // console.log("Getting forwarding history")
const { response } = await this.lightning.forwardingHistory({ indexOffset, numMaxEvents: 0, startTime: BigInt(startTime), endTime: BigInt(endTime), peerAliasLookup: false }, DeadLineMetadata()) const { response } = await this.lightning.forwardingHistory({ indexOffset, numMaxEvents: 0, startTime: BigInt(startTime), endTime: BigInt(endTime), peerAliasLookup: false }, DeadLineMetadata())
return response return response
@ -586,6 +626,9 @@ export default class {
} }
async GetLatestPaymentIndex(from = 0) { async GetLatestPaymentIndex(from = 0) {
if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) {
return from
}
// console.log("Getting latest payment index") // console.log("Getting latest payment index")
let indexOffset = BigInt(from) let indexOffset = BigInt(from)
while (true) { while (true) {

View file

@ -212,6 +212,11 @@ export default class {
addressPaidCb: AddressPaidCb = (txOutput, address, amount, used) => { addressPaidCb: AddressPaidCb = (txOutput, address, amount, used) => {
return this.storage.StartTransaction(async tx => { return this.storage.StartTransaction(async tx => {
// 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")
return
}
const { blockHeight } = await this.lnd.GetInfo() const { blockHeight } = await this.lnd.GetInfo()
const userAddress = await this.storage.paymentStorage.GetAddressOwner(address, tx) const userAddress = await this.storage.paymentStorage.GetAddressOwner(address, tx)
if (!userAddress) { if (!userAddress) {

View file

@ -71,6 +71,10 @@ export class LiquidityManager {
} }
afterInInvoicePaid = async () => { afterInInvoicePaid = async () => {
// Skip channel ordering if using only liquidity provider
if (this.settings.getSettings().liquiditySettings.useOnlyLiquidityProvider) {
return
}
try { try {
await this.orderChannelIfNeeded() await this.orderChannelIfNeeded()
} catch (e: any) { } catch (e: any) {
@ -91,6 +95,10 @@ export class LiquidityManager {
afterOutInvoicePaid = async () => { } afterOutInvoicePaid = async () => { }
shouldDrainProvider = async () => { shouldDrainProvider = async () => {
// Skip draining when bypass is enabled
if (this.settings.getSettings().liquiditySettings.useOnlyLiquidityProvider) {
return
}
const maxW = await this.liquidityProvider.GetLatestMaxWithdrawable() const maxW = await this.liquidityProvider.GetLatestMaxWithdrawable()
const { remote } = await this.lnd.ChannelBalance() const { remote } = await this.lnd.ChannelBalance()
const drainable = Math.min(maxW, remote) const drainable = Math.min(maxW, remote)
@ -148,6 +156,10 @@ export class LiquidityManager {
shouldOpenChannel = async (): Promise<{ shouldOpen: false } | { shouldOpen: true, maxSpendable: number }> => { shouldOpenChannel = async (): Promise<{ shouldOpen: false } | { shouldOpen: true, maxSpendable: number }> => {
// Skip channel operations if using only liquidity provider
if (this.settings.getSettings().liquiditySettings.useOnlyLiquidityProvider) {
return { shouldOpen: false }
}
const threshold = this.settings.getSettings().lspSettings.channelThreshold const threshold = this.settings.getSettings().lspSettings.channelThreshold
if (threshold === 0) { if (threshold === 0) {
return { shouldOpen: false } return { shouldOpen: false }

View file

@ -262,10 +262,18 @@ export class OfferManager {
async getNofferInvoice(offerReq: NofferData, appId: string, clinkRequester?: { pub: string, eventId: string }): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> { async getNofferInvoice(offerReq: NofferData, appId: string, clinkRequester?: { pub: string, eventId: string }): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
try { try {
const { remote } = await this.lnd.ChannelBalance() // When bypass is enabled, use provider balance instead of LND channel balance
let maxSendable = remote let maxSendable = 0
if (remote === 0 && (await this.liquidityManager.liquidityProvider.IsReady())) { if (this.liquidityManager.settings.getSettings().liquiditySettings.useOnlyLiquidityProvider) {
maxSendable = 10_000_000 if (await this.liquidityManager.liquidityProvider.IsReady()) {
maxSendable = 10_000_000
}
} else {
const { remote } = await this.lnd.ChannelBalance()
maxSendable = remote
if (remote === 0 && (await this.liquidityManager.liquidityProvider.IsReady())) {
maxSendable = 10_000_000
}
} }
const split = offerReq.offer.split(':') const split = offerReq.offer.split(':')
if (split.length === 1) { if (split.length === 1) {

View file

@ -115,6 +115,11 @@ export default class {
} }
checkPendingLndPayment = async (log: PubLogger, p: UserInvoicePayment) => { checkPendingLndPayment = async (log: PubLogger, p: UserInvoicePayment) => {
// Skip LND payment checks when bypass is enabled
if (this.liquidityManager.settings.getSettings().liquiditySettings.useOnlyLiquidityProvider) {
log("USE_ONLY_LIQUIDITY_PROVIDER enabled, skipping LND payment check for", p.serial_id)
return
}
const decoded = await this.lnd.DecodeInvoice(p.invoice) const decoded = await this.lnd.DecodeInvoice(p.invoice)
const payment = await this.lnd.GetPaymentFromHash(decoded.paymentHash) const payment = await this.lnd.GetPaymentFromHash(decoded.paymentHash)
if (!payment || payment.paymentHash !== decoded.paymentHash) { if (!payment || payment.paymentHash !== decoded.paymentHash) {

View file

@ -211,6 +211,10 @@ export class Watchdog {
} }
PaymentRequested = async () => { PaymentRequested = async () => {
// Skip watchdog check when bypass is enabled
if (this.liquidProvider.getSettings().useOnlyLiquidityProvider) {
return
}
if (!this.ready) { if (!this.ready) {
throw new Error("Watchdog not ready") throw new Error("Watchdog not ready")
} }