addressbook
This commit is contained in:
parent
aeae71baf8
commit
43fc36ac01
2 changed files with 78 additions and 48 deletions
|
|
@ -53,7 +53,7 @@ export default class {
|
|||
this.storage = new Storage(settings.storageSettings)
|
||||
this.lnd = NewLightningHandler(settings.lndSettings, this.addressPaidCb, this.invoicePaidCb)
|
||||
|
||||
this.paymentManager = new PaymentManager(this.storage, this.lnd, this.settings)
|
||||
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.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager)
|
||||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { bech32 } from 'bech32'
|
||||
import crypto from 'crypto'
|
||||
import Storage from '../storage/index.js'
|
||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
import { MainSettings } from './settings.js'
|
||||
|
|
@ -6,6 +7,10 @@ import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorag
|
|||
import { LightningHandler } from '../lnd/index.js'
|
||||
import { Application } from '../storage/entity/Application.js'
|
||||
import { getLogger } from '../helpers/logger.js'
|
||||
import { UserReceivingAddress } from '../storage/entity/UserReceivingAddress.js'
|
||||
import { AddressPaidCb, InvoicePaidCb, PaidInvoice } from '../lnd/settings.js'
|
||||
import { UserReceivingInvoice } from '../storage/entity/UserReceivingInvoice.js'
|
||||
import { SendCoinsResponse } from '../../../proto/lnd/lightning.js'
|
||||
interface UserOperationInfo {
|
||||
serial_id: number
|
||||
paid_amount: number
|
||||
|
|
@ -22,10 +27,14 @@ export default class {
|
|||
storage: Storage
|
||||
settings: MainSettings
|
||||
lnd: LightningHandler
|
||||
constructor(storage: Storage, lnd: LightningHandler, settings: MainSettings) {
|
||||
addressPaidCb: AddressPaidCb
|
||||
invoicePaidCb: InvoicePaidCb
|
||||
constructor(storage: Storage, lnd: LightningHandler, settings: MainSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) {
|
||||
this.storage = storage
|
||||
this.settings = settings
|
||||
this.lnd = lnd
|
||||
this.addressPaidCb = addressPaidCb
|
||||
this.invoicePaidCb = invoicePaidCb
|
||||
}
|
||||
|
||||
getServiceFee(action: Types.UserOperationType, amount: number, appUser: boolean): number {
|
||||
|
|
@ -116,7 +125,13 @@ export default class {
|
|||
amount: Number(decoded.numSatoshis)
|
||||
}
|
||||
}
|
||||
async PayInvoice(userId: string, req: Types.PayInvoiceRequest, linkedApplication?: Application): Promise<Types.PayInvoiceResponse> {
|
||||
|
||||
async PayInvoiceInternal(app: Application, userId: string, invoice: UserReceivingInvoice, amount: number, action: Types.UserOperationType): Promise<Types.PayAddressResponse> {
|
||||
|
||||
this.invoicePaidCb(invoice.invoice, amount)
|
||||
return { txId: "" }
|
||||
}
|
||||
async PayInvoice(userId: string, req: Types.PayInvoiceRequest, linkedApplication: Application): Promise<Types.PayInvoiceResponse> {
|
||||
const decoded = await this.lnd.DecodeInvoice(req.invoice)
|
||||
if (decoded.numSatoshis !== 0 && req.amount !== 0) {
|
||||
throw new Error("invoice has value, do not provide amount the the request")
|
||||
|
|
@ -125,55 +140,70 @@ export default class {
|
|||
throw new Error("invoice has no value, an amount must be provided in the request")
|
||||
}
|
||||
const payAmount = req.amount !== 0 ? req.amount : Number(decoded.numSatoshis)
|
||||
if (!linkedApplication) {
|
||||
throw new Error("only application operations are supported") // TODO - make this check obsolete
|
||||
}
|
||||
const isAppUserPayment = userId !== linkedApplication.owner.user_id
|
||||
const serviceFee = this.getServiceFee(Types.UserOperationType.OUTGOING_INVOICE, payAmount, isAppUserPayment)
|
||||
const totalAmountToDecrement = payAmount + serviceFee
|
||||
|
||||
const internalInvoice = await this.storage.paymentStorage.GetInvoiceOwner(req.invoice)
|
||||
let payment: PaidInvoice | null = null
|
||||
if (!internalInvoice) {
|
||||
const routingFeeLimit = this.lnd.GetFeeLimitAmount(payAmount)
|
||||
await this.lockUserWithMinBalance(userId, totalAmountToDecrement + routingFeeLimit)
|
||||
let payment
|
||||
try {
|
||||
payment = await this.lnd.PayInvoice(req.invoice, req.amount, routingFeeLimit)
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + payment.feeSat)
|
||||
await this.storage.userStorage.UnlockUser(userId)
|
||||
} catch (err) {
|
||||
await this.storage.userStorage.UnlockUser(userId)
|
||||
throw err
|
||||
}
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + Number(payment.feeSat))
|
||||
} else {
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement)
|
||||
this.invoicePaidCb(req.invoice, payAmount)
|
||||
}
|
||||
if (isAppUserPayment && serviceFee > 0) {
|
||||
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee)
|
||||
}
|
||||
await this.storage.paymentStorage.AddUserInvoicePayment(userId, req.invoice, payAmount, Number(payment.feeSat), serviceFee)
|
||||
const routingFees = payment ? payment.feeSat : 0
|
||||
await this.storage.paymentStorage.AddUserInvoicePayment(userId, req.invoice, payAmount, routingFees, serviceFee)
|
||||
return {
|
||||
preimage: payment.paymentPreimage,
|
||||
amount_paid: Number(payment.valueSat)
|
||||
preimage: payment ? payment.paymentPreimage : "",
|
||||
amount_paid: payment ? Number(payment.valueSat) : payAmount
|
||||
}
|
||||
}
|
||||
|
||||
async PayAddress(ctx: Types.UserContext, req: Types.PayAddressRequest): Promise<Types.PayAddressResponse> {
|
||||
const userId = ctx.user_id
|
||||
const app = await this.storage.applicationStorage.GetApplication(ctx.app_id)
|
||||
|
||||
async PayAddress(userId: string, req: Types.PayAddressRequest, linkedApplication: Application): Promise<Types.PayAddressResponse> {
|
||||
const serviceFee = this.getServiceFee(Types.UserOperationType.OUTGOING_TX, req.amoutSats, false)
|
||||
const isAppUserPayment = userId !== linkedApplication.owner.user_id
|
||||
const internalAddress = await this.storage.paymentStorage.GetAddressOwner(req.address)
|
||||
let txId = ""
|
||||
let chainFees = 0
|
||||
if (!internalAddress) {
|
||||
const estimate = await this.lnd.EstimateChainFees(req.address, req.amoutSats, 1)
|
||||
const vBytes = Math.ceil(Number(estimate.feeSat / estimate.satPerVbyte))
|
||||
const chainFees = vBytes * req.satsPerVByte
|
||||
chainFees = vBytes * req.satsPerVByte
|
||||
const total = req.amoutSats + chainFees
|
||||
const serviceFee = this.getServiceFee(Types.UserOperationType.OUTGOING_INVOICE, req.amoutSats, false)
|
||||
await this.lockUserWithMinBalance(userId, total + serviceFee)
|
||||
let payment
|
||||
try {
|
||||
payment = await this.lnd.PayAddress(req.address, req.amoutSats, req.satsPerVByte)
|
||||
const payment = await this.lnd.PayAddress(req.address, req.amoutSats, req.satsPerVByte)
|
||||
txId = payment.txid
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, total + serviceFee)
|
||||
await this.storage.userStorage.UnlockUser(userId)
|
||||
} catch (err) {
|
||||
await this.storage.userStorage.UnlockUser(userId)
|
||||
throw err
|
||||
}
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, total + serviceFee)
|
||||
await this.storage.paymentStorage.AddUserTransactionPayment(userId, req.address, payment.txid, 0, req.amoutSats, chainFees, serviceFee)
|
||||
} else {
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, req.amoutSats + serviceFee)
|
||||
this.addressPaidCb({ hash: crypto.randomBytes(32).toString("hex"), index: 0 }, req.address, req.amoutSats)
|
||||
}
|
||||
|
||||
if (isAppUserPayment && serviceFee > 0) {
|
||||
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee)
|
||||
}
|
||||
await this.storage.paymentStorage.AddUserTransactionPayment(userId, req.address, txId, 0, req.amoutSats, chainFees, serviceFee)
|
||||
return {
|
||||
txId: payment.txid
|
||||
txId: txId
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,8 +241,11 @@ export default class {
|
|||
|
||||
async HandleLnurlWithdraw(k1: string, invoice: string): Promise<void> {
|
||||
const key = await this.storage.paymentStorage.UseUserEphemeralKey(k1, 'withdraw')
|
||||
if (!key.linkedApplication) {
|
||||
throw new Error("found lnurl key entry with no linked application")
|
||||
}
|
||||
try {
|
||||
await this.PayInvoice(key.user.user_id, { invoice: invoice, amount: 0 })
|
||||
await this.PayInvoice(key.user.user_id, { invoice: invoice, amount: 0 }, key.linkedApplication)
|
||||
} catch (err: any) {
|
||||
console.error("error sending payment for lnurl withdraw to ", key.user.user_id, err)
|
||||
throw new Error("failed to pay invoice")
|
||||
|
|
@ -330,18 +363,13 @@ export default class {
|
|||
}
|
||||
}
|
||||
|
||||
async SendUserToUserPayment(fromUserId: string, toUserId: string, amount: number, linkedApplication?: Application) {
|
||||
if (!linkedApplication) {
|
||||
throw new Error("only application operations are supported") // TODO - make this check obsolete
|
||||
}
|
||||
async SendUserToUserPayment(fromUserId: string, toUserId: string, amount: number, linkedApplication: Application): Promise<number> {
|
||||
let sentAmount = 0
|
||||
await this.storage.StartTransaction(async tx => {
|
||||
const fromUser = await this.storage.userStorage.GetUser(fromUserId, tx)
|
||||
const toUser = await this.storage.userStorage.GetUser(toUserId, tx)
|
||||
if (fromUser.balance_sats < amount) {
|
||||
throw new Error("not enough balance to send user to user payment")
|
||||
}
|
||||
if (!linkedApplication) {
|
||||
throw new Error("only application operations are supported") // TODO - make this check obsolete
|
||||
throw new Error("not enough balance to send payment")
|
||||
}
|
||||
const isAppUserPayment = fromUser.user_id !== linkedApplication.owner.user_id
|
||||
let fee = this.getServiceFee(Types.UserOperationType.OUTGOING_USER_TO_USER, amount, isAppUserPayment)
|
||||
|
|
@ -352,7 +380,9 @@ export default class {
|
|||
if (isAppUserPayment && fee > 0) {
|
||||
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, fee)
|
||||
}
|
||||
sentAmount = toIncrement
|
||||
})
|
||||
return sentAmount
|
||||
}
|
||||
|
||||
encodeLnurl(base: string) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue