dont lose payments
This commit is contained in:
parent
0d37b1d72b
commit
5969e8fecf
9 changed files with 59 additions and 29 deletions
|
|
@ -111,7 +111,7 @@ export default class {
|
|||
tx.outputDetails.forEach(output => {
|
||||
if (output.isOurAddress) {
|
||||
this.log("received chan TX", Number(output.amount), "sats")
|
||||
this.addressPaidCb({ hash: tx.txHash, index: Number(output.outputIndex) }, output.address, Number(output.amount))
|
||||
this.addressPaidCb({ hash: tx.txHash, index: Number(output.outputIndex) }, output.address, Number(output.amount), false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -133,7 +133,7 @@ export default class {
|
|||
if (invoice.state === Invoice_InvoiceState.SETTLED) {
|
||||
this.log("An invoice was paid for", Number(invoice.amtPaidSat), "sats")
|
||||
this.latestKnownSettleIndex = Number(invoice.settleIndex)
|
||||
this.invoicePaidCb(invoice.paymentRequest, Number(invoice.amtPaidSat))
|
||||
this.invoicePaidCb(invoice.paymentRequest, Number(invoice.amtPaidSat), false)
|
||||
}
|
||||
})
|
||||
stream.responses.onError(error => {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ type TxOutput = {
|
|||
index: number
|
||||
}
|
||||
|
||||
export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number) => void
|
||||
export type InvoicePaidCb = (paymentRequest: string, amount: number) => void
|
||||
export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number, internal: boolean) => void
|
||||
export type InvoicePaidCb = (paymentRequest: string, amount: number, internal: boolean) => void
|
||||
|
||||
export type NodeInfo = {
|
||||
alias: string
|
||||
|
|
|
|||
|
|
@ -59,14 +59,23 @@ export default class {
|
|||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||
}
|
||||
|
||||
addressPaidCb: AddressPaidCb = (txOutput, address, amount) => {
|
||||
addressPaidCb: AddressPaidCb = (txOutput, address, amount, internal) => {
|
||||
this.storage.StartTransaction(async tx => {
|
||||
const userAddress = await this.storage.paymentStorage.GetAddressOwner(address, tx)
|
||||
if (!userAddress) { return }
|
||||
const fee = this.paymentManager.getServiceFee(Types.UserOperationType.INCOMING_TX, amount, false)
|
||||
const log = getLogger({})
|
||||
if (!userAddress.linkedApplication) {
|
||||
log("ERROR", "an address was paid, that has no linked application")
|
||||
return
|
||||
}
|
||||
const isAppUserPayment = userAddress.user.user_id !== userAddress.linkedApplication.owner.user_id
|
||||
let fee = this.paymentManager.getServiceFee(Types.UserOperationType.INCOMING_TX, amount, isAppUserPayment)
|
||||
if (userAddress.linkedApplication && userAddress.linkedApplication.owner.user_id === userAddress.user.user_id) {
|
||||
fee = 0
|
||||
}
|
||||
try {
|
||||
// This call will fail if the transaction is already registered
|
||||
const addedTx = await this.storage.paymentStorage.AddAddressReceivingTransaction(userAddress, txOutput.hash, txOutput.index, amount, fee, tx)
|
||||
const addedTx = await this.storage.paymentStorage.AddAddressReceivingTransaction(userAddress, txOutput.hash, txOutput.index, amount, fee, internal, tx)
|
||||
await this.storage.userStorage.IncrementUserBalance(userAddress.user.user_id, addedTx.paid_amount - fee, tx)
|
||||
this.triggerSubs(userAddress.user.user_id, { amount, paidAtUnix: Date.now() / 1000, inbound: true, type: Types.UserOperationType.INCOMING_TX, identifier: userAddress.address })
|
||||
} catch {
|
||||
|
|
@ -75,11 +84,13 @@ export default class {
|
|||
})
|
||||
}
|
||||
|
||||
invoicePaidCb: InvoicePaidCb = (paymentRequest, amount) => {
|
||||
invoicePaidCb: InvoicePaidCb = (paymentRequest, amount, internal) => {
|
||||
this.storage.StartTransaction(async tx => {
|
||||
const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(paymentRequest, tx)
|
||||
if (!userInvoice || userInvoice.paid_at_unix > 0) { return }
|
||||
const log = getLogger({})
|
||||
const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(paymentRequest, tx)
|
||||
if (!userInvoice) { return }
|
||||
if (userInvoice.paid_at_unix > 0 && internal) { log("cannot pay internally, invoice already paid"); return }
|
||||
if (userInvoice.paid_at_unix > 0 && !internal && userInvoice.paidByLnd) { log("invoice already paid by lnd"); return }
|
||||
if (!userInvoice.linkedApplication) {
|
||||
log("ERROR", "an invoice was paid, that has no linked application")
|
||||
return
|
||||
|
|
@ -90,8 +101,7 @@ export default class {
|
|||
fee = 0
|
||||
}
|
||||
try {
|
||||
// This call will fail if the invoice is already registered
|
||||
await this.storage.paymentStorage.FlagInvoiceAsPaid(userInvoice, amount, fee, tx)
|
||||
await this.storage.paymentStorage.FlagInvoiceAsPaid(userInvoice, amount, fee, internal, tx)
|
||||
|
||||
await this.storage.userStorage.IncrementUserBalance(userInvoice.user.user_id, amount - fee, tx)
|
||||
if (isAppUserPayment && fee > 0) {
|
||||
|
|
|
|||
|
|
@ -126,11 +126,6 @@ export default class {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -157,14 +152,17 @@ export default class {
|
|||
throw err
|
||||
}
|
||||
} else {
|
||||
if (internalInvoice.paid_at_unix > 0) {
|
||||
throw new Error("this invoice was already paid")
|
||||
}
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement)
|
||||
this.invoicePaidCb(req.invoice, payAmount)
|
||||
this.invoicePaidCb(req.invoice, payAmount, true)
|
||||
}
|
||||
if (isAppUserPayment && serviceFee > 0) {
|
||||
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee)
|
||||
}
|
||||
const routingFees = payment ? payment.feeSat : 0
|
||||
await this.storage.paymentStorage.AddUserInvoicePayment(userId, req.invoice, payAmount, routingFees, serviceFee)
|
||||
await this.storage.paymentStorage.AddUserInvoicePayment(userId, req.invoice, payAmount, routingFees, serviceFee, !!internalInvoice)
|
||||
return {
|
||||
preimage: payment ? payment.paymentPreimage : "",
|
||||
amount_paid: payment ? Number(payment.valueSat) : payAmount
|
||||
|
|
@ -195,13 +193,13 @@ export default class {
|
|||
}
|
||||
} else {
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, req.amoutSats + serviceFee)
|
||||
this.addressPaidCb({ hash: crypto.randomBytes(32).toString("hex"), index: 0 }, req.address, req.amoutSats)
|
||||
this.addressPaidCb({ hash: crypto.randomBytes(32).toString("hex"), index: 0 }, req.address, req.amoutSats, true)
|
||||
}
|
||||
|
||||
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)
|
||||
await this.storage.paymentStorage.AddUserTransactionPayment(userId, req.address, txId, 0, req.amoutSats, chainFees, serviceFee, !!internalAddress)
|
||||
return {
|
||||
txId: txId
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ export class AddressReceivingTransaction {
|
|||
@Column()
|
||||
paid_at_unix: number
|
||||
|
||||
@Column()
|
||||
internal: boolean
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ export class UserInvoicePayment {
|
|||
@Column()
|
||||
paid_at_unix: number
|
||||
|
||||
@Column()
|
||||
internal: boolean
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ export class UserReceivingInvoice {
|
|||
@Column({ default: 0 })
|
||||
paid_at_unix: number
|
||||
|
||||
@Column()
|
||||
internal: boolean
|
||||
|
||||
@Column()
|
||||
paidByLnd: boolean
|
||||
|
||||
@Column({ default: "" })
|
||||
callbackUrl: string
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ export class UserTransactionPayment {
|
|||
@Column()
|
||||
paid_at_unix: number
|
||||
|
||||
@Column()
|
||||
internal: boolean
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,15 @@ export default class {
|
|||
this.DB = DB
|
||||
this.userStorage = userStorage
|
||||
}
|
||||
async AddAddressReceivingTransaction(address: UserReceivingAddress, txHash: string, outputIndex: number, amount: number, serviceFee: number, entityManager = this.DB) {
|
||||
async AddAddressReceivingTransaction(address: UserReceivingAddress, txHash: string, outputIndex: number, amount: number, serviceFee: number, internal: boolean, entityManager = this.DB) {
|
||||
const newAddressTransaction = entityManager.getRepository(AddressReceivingTransaction).create({
|
||||
user_address: address,
|
||||
tx_hash: txHash,
|
||||
output_index: outputIndex,
|
||||
paid_amount: amount,
|
||||
service_fee: serviceFee,
|
||||
paid_at_unix: Math.floor(Date.now() / 1000)
|
||||
paid_at_unix: Math.floor(Date.now() / 1000),
|
||||
internal
|
||||
})
|
||||
return entityManager.getRepository(AddressReceivingTransaction).save(newAddressTransaction)
|
||||
}
|
||||
|
|
@ -57,8 +58,12 @@ export default class {
|
|||
return entityManager.getRepository(UserReceivingAddress).save(newUserAddress)
|
||||
}
|
||||
|
||||
async FlagInvoiceAsPaid(invoice: UserReceivingInvoice, amount: number, serviceFee: number, entityManager = this.DB) {
|
||||
return entityManager.getRepository(UserReceivingInvoice).update(invoice.serial_id, { paid_at_unix: Math.floor(Date.now() / 1000), paid_amount: amount, service_fee: serviceFee })
|
||||
async FlagInvoiceAsPaid(invoice: UserReceivingInvoice, amount: number, serviceFee: number, internal: boolean, entityManager = this.DB) {
|
||||
const i: Partial<UserReceivingInvoice> = { paid_at_unix: Math.floor(Date.now() / 1000), paid_amount: amount, service_fee: serviceFee, internal }
|
||||
if (!internal) {
|
||||
i.paidByLnd = true
|
||||
}
|
||||
return entityManager.getRepository(UserReceivingInvoice).update(invoice.serial_id, i)
|
||||
}
|
||||
|
||||
GetUserInvoicesFlaggedAsPaid(userId: string, fromIndex: number, entityManager = this.DB): Promise<UserReceivingInvoice[]> {
|
||||
|
|
@ -105,14 +110,15 @@ export default class {
|
|||
})
|
||||
}
|
||||
|
||||
async AddUserInvoicePayment(userId: string, invoice: string, amount: number, routingFees: number, serviceFees: number, entityManager = this.DB): Promise<UserInvoicePayment> {
|
||||
async AddUserInvoicePayment(userId: string, invoice: string, amount: number, routingFees: number, serviceFees: number, internal: boolean, entityManager = this.DB): Promise<UserInvoicePayment> {
|
||||
const newPayment = entityManager.getRepository(UserInvoicePayment).create({
|
||||
user: await this.userStorage.GetUser(userId),
|
||||
paid_amount: amount,
|
||||
invoice,
|
||||
routing_fees: routingFees,
|
||||
service_fees: serviceFees,
|
||||
paid_at_unix: Math.floor(Date.now() / 1000)
|
||||
paid_at_unix: Math.floor(Date.now() / 1000),
|
||||
internal
|
||||
})
|
||||
return entityManager.getRepository(UserInvoicePayment).save(newPayment)
|
||||
}
|
||||
|
|
@ -132,7 +138,7 @@ export default class {
|
|||
})
|
||||
}
|
||||
|
||||
async AddUserTransactionPayment(userId: string, address: string, txHash: string, txOutput: number, amount: number, chainFees: number, serviceFees: number, entityManager = this.DB): Promise<UserTransactionPayment> {
|
||||
async AddUserTransactionPayment(userId: string, address: string, txHash: string, txOutput: number, amount: number, chainFees: number, serviceFees: number, internal: boolean, entityManager = this.DB): Promise<UserTransactionPayment> {
|
||||
const newTx = entityManager.getRepository(UserTransactionPayment).create({
|
||||
user: await this.userStorage.GetUser(userId),
|
||||
address,
|
||||
|
|
@ -141,7 +147,8 @@ export default class {
|
|||
output_index: txOutput,
|
||||
tx_hash: txHash,
|
||||
service_fees: serviceFees,
|
||||
paid_at_unix: Math.floor(Date.now() / 1000)
|
||||
paid_at_unix: Math.floor(Date.now() / 1000),
|
||||
internal
|
||||
})
|
||||
return entityManager.getRepository(UserTransactionPayment).save(newTx)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue