commit
1debe0baf4
8 changed files with 16 additions and 206 deletions
|
|
@ -1,10 +1,5 @@
|
|||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
import { GetInfoResponse, NewAddressResponse, AddInvoiceResponse, PayReq, Payment, SendCoinsResponse, EstimateFeeResponse, TransactionDetails, ClosedChannelsResponse, ListChannelsResponse, PendingChannelsResponse, ListInvoiceResponse, ListPaymentsResponse, ChannelBalanceResponse, WalletBalanceResponse } from '../../../proto/lnd/lightning.js'
|
||||
import { EnvMustBeNonEmptyString, EnvMustBeInteger, EnvCanBeBoolean } from '../helpers/envParser.js'
|
||||
import { AddressPaidCb, BalanceInfo, DecodedInvoice, HtlcCb, Invoice, InvoicePaidCb, LndSettings, NewBlockCb, NodeInfo, PaidInvoice } from './settings.js'
|
||||
import LND from './lnd.js'
|
||||
import MockLnd from './mock.js'
|
||||
import { getLogger } from '../helpers/logger.js'
|
||||
import { LndSettings } from './settings.js'
|
||||
export const LoadLndSettingsFromEnv = (): LndSettings => {
|
||||
const lndAddr = EnvMustBeNonEmptyString("LND_ADDRESS")
|
||||
const lndCertPath = EnvMustBeNonEmptyString("LND_CERT_PATH")
|
||||
|
|
@ -14,42 +9,3 @@ export const LoadLndSettingsFromEnv = (): LndSettings => {
|
|||
const mockLnd = EnvCanBeBoolean("MOCK_LND")
|
||||
return { mainNode: { lndAddr, lndCertPath, lndMacaroonPath }, feeRateLimit, feeFixedLimit, mockLnd }
|
||||
}
|
||||
export interface LightningHandler {
|
||||
Stop(): void
|
||||
Warmup(): Promise<void>
|
||||
GetInfo(): Promise<NodeInfo>
|
||||
Health(): Promise<void>
|
||||
NewAddress(addressType: Types.AddressType): Promise<NewAddressResponse>
|
||||
NewInvoice(value: number, memo: string, expiry: number): Promise<Invoice>
|
||||
DecodeInvoice(paymentRequest: string): Promise<DecodedInvoice>
|
||||
GetFeeLimitAmount(amount: number): number
|
||||
GetMaxWithinLimit(amount: number): number
|
||||
PayInvoice(invoice: string, amount: number, feeLimit: number): Promise<PaidInvoice>
|
||||
EstimateChainFees(address: string, amount: number, targetConf: number): Promise<EstimateFeeResponse>
|
||||
PayAddress(address: string, amount: number, satPerVByte: number, label?: string): Promise<SendCoinsResponse>
|
||||
//OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number): Promise<string>
|
||||
SetMockInvoiceAsPaid(invoice: string, amount: number): Promise<void>
|
||||
ChannelBalance(): Promise<{ local: number, remote: number }>
|
||||
GetTransactions(startHeight: number): Promise<TransactionDetails>
|
||||
GetBalance(): Promise<BalanceInfo>
|
||||
GetWalletBalance(): Promise<WalletBalanceResponse>
|
||||
GetChannelBalance(): Promise<ChannelBalanceResponse>
|
||||
ListClosedChannels(): Promise<ClosedChannelsResponse>
|
||||
ListChannels(): Promise<ListChannelsResponse>
|
||||
ListPendingChannels(): Promise<PendingChannelsResponse>
|
||||
GetForwardingHistory(indexOffset: number): Promise<{ fee: number, chanIdIn: string, chanIdOut: string, timestampNs: number, offset: number }[]>
|
||||
GetAllPaidInvoices(max: number): Promise<ListInvoiceResponse>
|
||||
GetAllPayments(max: number): Promise<ListPaymentsResponse>
|
||||
LockOutgoingOperations(): void
|
||||
UnlockOutgoingOperations(): void
|
||||
}
|
||||
|
||||
export default (settings: LndSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb, htlcCb: HtlcCb): LightningHandler => {
|
||||
if (settings.mockLnd) {
|
||||
getLogger({})("registering mock lnd handler")
|
||||
return new MockLnd(settings, addressPaidCb, invoicePaidCb, newBlockCb)
|
||||
} else {
|
||||
getLogger({})("registering prod lnd handler")
|
||||
return new LND(settings, addressPaidCb, invoicePaidCb, newBlockCb, htlcCb)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
//const grpc = require('@grpc/grpc-js');
|
||||
import { credentials, Metadata } from '@grpc/grpc-js'
|
||||
import { GrpcTransport } from "@protobuf-ts/grpc-transport";
|
||||
import fs from 'fs'
|
||||
import crypto from 'crypto'
|
||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
import { LightningClient } from '../../../proto/lnd/lightning.client.js'
|
||||
import { InvoicesClient } from '../../../proto/lnd/invoices.client.js'
|
||||
import { RouterClient } from '../../../proto/lnd/router.client.js'
|
||||
import { GetInfoResponse, AddressType, NewAddressResponse, AddInvoiceResponse, Invoice_InvoiceState, PayReq, Payment_PaymentStatus, Payment, PaymentFailureReason, SendCoinsResponse, EstimateFeeResponse, TransactionDetails, ClosedChannelsResponse, ListChannelsResponse, PendingChannelsResponse, ListInvoiceResponse, ListPaymentsResponse, ChannelBalanceResponse, WalletBalanceResponse } from '../../../proto/lnd/lightning.js'
|
||||
import { OpenChannelReq } from './openChannelReq.js';
|
||||
import { AddInvoiceReq } from './addInvoiceReq.js';
|
||||
import { PayInvoiceReq } from './payInvoiceReq.js';
|
||||
import { SendCoinsReq } from './sendCoinsReq.js';
|
||||
import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice, NewBlockCb, BalanceInfo } from './settings.js';
|
||||
import { getLogger } from '../helpers/logger.js';
|
||||
|
||||
export default class {
|
||||
invoicesAwaiting: Record<string /* invoice */, { value: number, memo: string, expiryUnix: number }> = {}
|
||||
settings: LndSettings
|
||||
abortController = new AbortController()
|
||||
addressPaidCb: AddressPaidCb
|
||||
invoicePaidCb: InvoicePaidCb
|
||||
constructor(settings: LndSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb) {
|
||||
this.settings = settings
|
||||
this.addressPaidCb = addressPaidCb
|
||||
this.invoicePaidCb = invoicePaidCb
|
||||
}
|
||||
|
||||
async SetMockInvoiceAsPaid(invoice: string, amount: number): Promise<void> {
|
||||
const decoded = await this.DecodeInvoice(invoice)
|
||||
if (decoded.numSatoshis && amount) {
|
||||
throw new Error("non zero amount provided to pay invoice but invoice has value already")
|
||||
}
|
||||
this.invoicePaidCb(invoice, decoded.numSatoshis || amount, false)
|
||||
delete this.invoicesAwaiting[invoice]
|
||||
}
|
||||
GetChannelBalance(): Promise<ChannelBalanceResponse> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
Stop() { }
|
||||
async Warmup() { }
|
||||
|
||||
async GetWalletBalance(): Promise<WalletBalanceResponse> { throw new Error("ListClosedChannels disabled in mock mode") }
|
||||
async ListClosedChannels(): Promise<ClosedChannelsResponse> { throw new Error("ListClosedChannels disabled in mock mode") }
|
||||
async ListChannels(): Promise<ListChannelsResponse> { throw new Error("ListChannels disabled in mock mode") }
|
||||
async ListPendingChannels(): Promise<PendingChannelsResponse> { throw new Error("ListPendingChannels disabled in mock mode") }
|
||||
async GetForwardingHistory(indexOffset: number): Promise<{ fee: number, chanIdIn: string, chanIdOut: string, timestampNs: number, offset: number }[]> { throw new Error("GetForwardingHistory disabled in mock mode") }
|
||||
|
||||
async GetInfo(): Promise<NodeInfo> {
|
||||
return { alias: "mock", syncedToChain: true, syncedToGraph: true, blockHeight: 1, blockHash: "", identityPubkey: "mock", uris: [] }
|
||||
}
|
||||
|
||||
async Health(): Promise<void> { }
|
||||
|
||||
async NewAddress(addressType: Types.AddressType): Promise<NewAddressResponse> {
|
||||
throw new Error("NewAddress disabled in mock mode")
|
||||
}
|
||||
|
||||
async NewInvoice(value: number, memo: string, expiry: number): Promise<Invoice> {
|
||||
const mockInvoice = "lnbcrtmockin" + crypto.randomBytes(32).toString('hex')
|
||||
this.invoicesAwaiting[mockInvoice] = { value, memo, expiryUnix: expiry + Date.now() / 1000 }
|
||||
return { payRequest: mockInvoice }
|
||||
}
|
||||
|
||||
async DecodeInvoice(paymentRequest: string): Promise<DecodedInvoice> {
|
||||
if (paymentRequest.startsWith('lnbcrtmockout')) {
|
||||
const amt = this.decodeOutboundInvoice(paymentRequest)
|
||||
return { numSatoshis: amt, paymentHash: paymentRequest }
|
||||
}
|
||||
const i = this.invoicesAwaiting[paymentRequest]
|
||||
if (!i) {
|
||||
throw new Error("invoice not found")
|
||||
}
|
||||
return { numSatoshis: i.value, paymentHash: paymentRequest }
|
||||
}
|
||||
|
||||
GetFeeLimitAmount(amount: number): number {
|
||||
return Math.ceil(amount * this.settings.feeRateLimit + this.settings.feeFixedLimit);
|
||||
}
|
||||
|
||||
GetMaxWithinLimit(amount: number): number {
|
||||
return Math.max(0, Math.floor(amount * (1 - this.settings.feeRateLimit) - this.settings.feeFixedLimit))
|
||||
}
|
||||
|
||||
decodeOutboundInvoice(invoice: string): number {
|
||||
if (!invoice.startsWith('lnbcrtmockout')) {
|
||||
throw new Error("invalid mock invoice provided for payment")
|
||||
}
|
||||
const amt = invoice.substring('lnbcrtmockout'.length).split("__")[0]
|
||||
if (isNaN(+amt)) {
|
||||
throw new Error("invalid mock invoice provided for payment")
|
||||
}
|
||||
return +amt
|
||||
}
|
||||
|
||||
async PayInvoice(invoice: string, amount: number, feeLimit: number): Promise<PaidInvoice> {
|
||||
const log = getLogger({})
|
||||
log('payng', invoice)
|
||||
await new Promise(res => setTimeout(res, 200))
|
||||
const amt = this.decodeOutboundInvoice(invoice)
|
||||
log('paid', invoice)
|
||||
return { feeSat: 1, paymentPreimage: "all_good", valueSat: amt || amount }
|
||||
}
|
||||
|
||||
async ChannelBalance(): Promise<{ local: number, remote: number }> {
|
||||
return { local: 100 * 1000 * 1000, remote: 100 * 1000 * 1000 }
|
||||
}
|
||||
|
||||
async EstimateChainFees(address: string, amount: number, targetConf: number): Promise<EstimateFeeResponse> {
|
||||
throw new Error("EstimateChainFees disabled in mock mode")
|
||||
}
|
||||
|
||||
async PayAddress(address: string, amount: number, satPerVByte: number, label = ""): Promise<SendCoinsResponse> {
|
||||
throw new Error("PayAddress disabled in mock mode")
|
||||
}
|
||||
|
||||
|
||||
async OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number): Promise<string> {
|
||||
throw new Error("OpenChannel disabled in mock mode")
|
||||
}
|
||||
|
||||
async GetTransactions(startHeight: number): Promise<TransactionDetails> {
|
||||
throw new Error("GetTransactions disabled in mock mode")
|
||||
}
|
||||
|
||||
GetBalance(): Promise<BalanceInfo> {
|
||||
throw new Error("GetBalance disabled in mock mode")
|
||||
}
|
||||
|
||||
async GetAllPaidInvoices(max: number): Promise<ListInvoiceResponse> {
|
||||
throw new Error("not implemented")
|
||||
}
|
||||
async GetAllPayments(max: number): Promise<ListPaymentsResponse> {
|
||||
throw new Error("not implemented")
|
||||
}
|
||||
LockOutgoingOperations() {
|
||||
throw new Error("not implemented")
|
||||
}
|
||||
UnlockOutgoingOperations() {
|
||||
throw new Error("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import ProductManager from './productManager.js'
|
|||
import ApplicationManager from './applicationManager.js'
|
||||
import PaymentManager, { PendingTx } from './paymentManager.js'
|
||||
import { MainSettings } from './settings.js'
|
||||
import NewLightningHandler, { LightningHandler } from "../lnd/index.js"
|
||||
import LND from "../lnd/lnd.js"
|
||||
import { AddressPaidCb, HtlcCb, InvoicePaidCb, NewBlockCb } from "../lnd/settings.js"
|
||||
import { getLogger, PubLogger } from "../helpers/logger.js"
|
||||
import AppUserManager from "./appUserManager.js"
|
||||
|
|
@ -26,7 +26,7 @@ type UserOperationsSub = {
|
|||
|
||||
export default class {
|
||||
storage: Storage
|
||||
lnd: LightningHandler
|
||||
lnd: LND
|
||||
settings: MainSettings
|
||||
userOperationsSub: UserOperationsSub | null = null
|
||||
productManager: ProductManager
|
||||
|
|
@ -41,7 +41,7 @@ export default class {
|
|||
this.settings = settings
|
||||
this.storage = storage
|
||||
|
||||
this.lnd = NewLightningHandler(settings.lndSettings, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb)
|
||||
this.lnd = new LND(settings.lndSettings, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb)
|
||||
this.metricsManager = new MetricsManager(this.storage, this.lnd)
|
||||
|
||||
this.paymentManager = new PaymentManager(this.storage, this.lnd, this.settings, this.addressPaidCb, this.invoicePaidCb)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Storage from '../storage/index.js'
|
|||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
import { MainSettings } from './settings.js'
|
||||
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
||||
import { LightningHandler } from '../lnd/index.js'
|
||||
import LND from '../lnd/lnd.js'
|
||||
import { Application } from '../storage/entity/Application.js'
|
||||
import { getLogger } from '../helpers/logger.js'
|
||||
import { UserReceivingAddress } from '../storage/entity/UserReceivingAddress.js'
|
||||
|
|
@ -42,12 +42,12 @@ export default class {
|
|||
|
||||
storage: Storage
|
||||
settings: MainSettings
|
||||
lnd: LightningHandler
|
||||
lnd: LND
|
||||
addressPaidCb: AddressPaidCb
|
||||
invoicePaidCb: InvoicePaidCb
|
||||
log = getLogger({ appName: "PaymentManager" })
|
||||
watchDog: Watchdog
|
||||
constructor(storage: Storage, lnd: LightningHandler, settings: MainSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) {
|
||||
constructor(storage: Storage, lnd: LND, settings: MainSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) {
|
||||
this.storage = storage
|
||||
this.settings = settings
|
||||
this.lnd = lnd
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Storage from '../storage/index.js'
|
||||
import { LightningHandler } from "../lnd/index.js"
|
||||
import LND from "../lnd/lnd.js"
|
||||
import { LoggedEvent } from '../storage/eventsLog.js'
|
||||
import { Invoice, Payment } from '../../../proto/lnd/lightning';
|
||||
import { getLogger } from '../helpers/logger.js';
|
||||
|
|
@ -12,7 +12,7 @@ type Reason = UniqueDecrementReasons | UniqueIncrementReasons | CommonReasons
|
|||
const incrementTwiceAllowed = ['fees', 'ban']
|
||||
export default class SanityChecker {
|
||||
storage: Storage
|
||||
lnd: LightningHandler
|
||||
lnd: LND
|
||||
|
||||
events: LoggedEvent[] = []
|
||||
invoices: Invoice[] = []
|
||||
|
|
@ -22,7 +22,7 @@ export default class SanityChecker {
|
|||
decrementEvents: Record<string, { userId: string, refund: number, failure: boolean }> = {}
|
||||
log = getLogger({ appName: "SanityChecker" })
|
||||
users: Record<string, { ts: number, updatedBalance: number }> = {}
|
||||
constructor(storage: Storage, lnd: LightningHandler) {
|
||||
constructor(storage: Storage, lnd: LND) {
|
||||
this.storage = storage
|
||||
this.lnd = lnd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { EnvCanBeInteger } from "../helpers/envParser.js";
|
||||
import { getLogger } from "../helpers/logger.js";
|
||||
import { LightningHandler } from "../lnd/index.js";
|
||||
import LND from "../lnd/lnd.js";
|
||||
import { ChannelBalance } from "../lnd/settings.js";
|
||||
import Storage from '../storage/index.js'
|
||||
export type WatchdogSettings = {
|
||||
|
|
@ -15,14 +15,14 @@ export class Watchdog {
|
|||
|
||||
initialLndBalance: number;
|
||||
initialUsersBalance: number;
|
||||
lnd: LightningHandler;
|
||||
lnd: LND;
|
||||
settings: WatchdogSettings;
|
||||
storage: Storage;
|
||||
latestCheckStart = 0
|
||||
log = getLogger({ appName: "watchdog" })
|
||||
enabled = false
|
||||
interval: NodeJS.Timer;
|
||||
constructor(settings: WatchdogSettings, lnd: LightningHandler, storage: Storage) {
|
||||
constructor(settings: WatchdogSettings, lnd: LND, storage: Storage) {
|
||||
this.lnd = lnd;
|
||||
this.settings = settings;
|
||||
this.storage = storage;
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ import { HtlcEvent, HtlcEvent_EventType } from '../../../proto/lnd/router.js'
|
|||
import { BalanceInfo } from '../lnd/settings.js'
|
||||
import { BalanceEvent } from '../storage/entity/BalanceEvent.js'
|
||||
import { ChannelBalanceEvent } from '../storage/entity/ChannelsBalanceEvent.js'
|
||||
import { LightningHandler } from '../lnd/index.js'
|
||||
import LND from '../lnd/lnd.js'
|
||||
import HtlcTracker from './htlcTracker.js'
|
||||
const maxEvents = 100_000
|
||||
export default class Handler {
|
||||
storage: Storage
|
||||
lnd: LightningHandler
|
||||
lnd: LND
|
||||
htlcTracker: HtlcTracker
|
||||
metrics: Types.UsageMetric[] = []
|
||||
constructor(storage: Storage, lnd: LightningHandler) {
|
||||
constructor(storage: Storage, lnd: LND) {
|
||||
this.storage = storage
|
||||
this.lnd = lnd
|
||||
this.htlcTracker = new HtlcTracker(this.storage)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import chaiString from 'chai-string'
|
|||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||
import SanityChecker from '../services/main/sanityChecker.js'
|
||||
import LND from '../services/lnd/lnd.js'
|
||||
import { LightningHandler } from '../services/lnd/index.js'
|
||||
chai.use(chaiString)
|
||||
export const expect = chai.expect
|
||||
export type Describe = (message: string, failure?: boolean) => void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue