Optimize transactions data updates

This commit is contained in:
minibits-cash
2025-06-20 14:02:35 +02:00
parent 1304158457
commit 73b1986ce1
13 changed files with 438 additions and 923 deletions
+28 -118
View File
@@ -1,9 +1,13 @@
import {Instance, SnapshotIn, SnapshotOut, flow, types} from 'mobx-state-tree'
import { Instance, SnapshotIn, SnapshotOut, types } from 'mobx-state-tree'
import { log } from '../services/logService'
import { MintUnit } from '../services/wallet/currency'
import { Database } from '../services'
/**
* Transaction model with MST actions for database updates.
* Note: Individual setter actions (setStatus, setFee, etc.) are deprecated.
* Use the generic update() action instead for all mutations.
*/
export interface TransactionRecord {
id: number
type: TransactionType
@@ -27,8 +31,8 @@ export interface TransactionRecord {
noteToSelf?: string | null
tags?: Array<string> | null
status: TransactionStatus
expiresAt?: Date | null
createdAt: Date
expiresAt?: Date | null
createdAt: Date
}
export type TransactionData = {
@@ -49,7 +53,7 @@ export enum TransactionType {
export enum TransactionStatus {
DRAFT = 'DRAFT',
PREPARED = 'PREPARED',
PREPARED_OFFLINE = 'PREPARED_OFFLINE', // offline receive, safer to have if sepearate from prepared
PREPARED_OFFLINE = 'PREPARED_OFFLINE', // offline receive, safer to have if separate from prepared
PENDING = 'PENDING',
REVERTED = 'REVERTED',
RECOVERED = 'RECOVERED',
@@ -60,7 +64,7 @@ export enum TransactionStatus {
}
export const TransactionModel = types
.model('Transaction', {
.model('Transaction', {
id: types.identifierNumber,
type: types.frozen<TransactionType>(),
amount: types.integer,
@@ -86,123 +90,29 @@ export const TransactionModel = types
expiresAt: types.maybe(types.maybeNull(types.Date)),
createdAt: types.optional(types.Date, new Date()),
})
.views(self => ({
}))
.views(self => ({}))
.actions(self => ({
setUnit(unit: MintUnit) { // migration
self.unit = unit
},
setIsExpired() {
self.status = TransactionStatus.EXPIRED
},
setStatus (
status: TransactionStatus,
data: string,
) {
// Update status and set related tx data in database
Database.updateStatus(self.id!, status, data)
// Update in the model
self.status = status
self.data = data
log.trace('[setStatus]', 'Transaction status and data updated', {id: self.id, status})
},
setBalanceAfter(balanceAfter: number) {
Database.updateBalanceAfter(self.id!, balanceAfter)
self.balanceAfter = balanceAfter
log.trace('[setBalanceAfter]', 'Transaction balanceAfter updated', {id: self.id, balanceAfter})
},
setFee(fee: number) {
Database.updateFee(self.id!, fee)
self.fee = fee
log.trace('[setFee]', 'Transaction fee updated', {id: self.id, fee})
},
setPaymentId(paymentId: string) {
Database.updatePaymentId(self.id!, paymentId)
self.paymentId = paymentId
log.trace('[setPaymentId]', 'Transaction paymentId updated', {id: self.id, paymentId})
},
setQuote(quote: string) {
Database.updateQuote(self.id!, quote)
self.quote = quote
log.trace('[setQuote]', 'Transaction quote updated', {id: self.id, quote})
},
setReceivedAmount(amount: number) {
Database.updateReceivedAmount(self.id!, amount)
self.amount = amount
log.trace('[setReceivedAmount]', 'Transaction amount updated', {id: self.id, amount})
},
setNote(note: string) {
Database.updateNote(self.id!, note)
self.noteToSelf = note
log.trace('[saveNote]', 'Transaction note updated', {id: self.id, note})
},
setZapRequest(zapRequest: string) {
Database.updateZapRequest(self.id!, zapRequest)
self.zapRequest = zapRequest
log.trace('[setZapRequest]', 'Transaction zapRequest updated', {id: self.id, zapRequest})
},
setPaymentRequest(paymentRequest: string) {
Database.updatePaymentRequest(self.id!, paymentRequest)
self.paymentRequest = paymentRequest
log.trace('[setZapRequest]', 'Transaction paymentRequest updated', {id: self.id, paymentRequest})
},
setExpiresAt(expiresAt: Date) {
Database.updateExpiresAt(self.id!, expiresAt)
self.expiresAt = expiresAt
log.trace('[setExpiresAt]', 'Transaction expiresAt updated', {id: self.id, expiresAt})
},
setSentFrom(sentFrom: string) {
Database.updateSentFrom(self.id!, sentFrom)
self.sentFrom = sentFrom
log.trace('[setSentFrom]', 'Transaction sentFrom updated', {id: self.id, sentFrom})
},
setSentTo(sentTo: string) {
Database.updateSentTo(self.id!, sentTo)
self.sentTo = sentTo
log.trace('[setSentTo]', 'Transaction sentTo updated', {id: self.id, sentTo})
},
setProfile(profile: string) {
Database.updateProfile(self.id!, profile)
self.profile = profile
log.trace('[setProfile]', 'Transaction profile updated', {id: self.id, profile})
},
setInputToken(inputToken: string) {
Database.updateInputToken(self.id!, inputToken)
pruneInputToken(inputToken: string) {
self.inputToken = inputToken.slice(0, 40)
log.trace('[setInputToken]', 'Transaction inputToken updated', {id: self.id, inputToken})
log.trace('[pruneInputToken]', 'Transaction inputToken pruned in store', { id: self.id })
},
setOutputToken(outputToken: string) {
Database.updateOutputToken(self.id!, outputToken)
pruneOutputToken(outputToken: string) {
self.outputToken = outputToken.slice(0, 40)
log.trace('[setOutputToken]', 'Transaction outputToken updated', {id: self.id})
log.trace('[pruneOutputToken]', 'Transaction outputToken pruned in store', { id: self.id })
},
setProof(proof: string) {
Database.updateProof(self.id!, proof)
self.proof = proof
log.trace('[setProof]', 'Transaction proof updated', {id: self.id, proof})
update(fields: Partial<TransactionRecord>) {
// Update multiple fields in database with a single query
Database.updateTransaction(self.id!, fields)
// Update the model to keep store in sync
Object.keys(fields).forEach(key => {
;(self as any)[key] = (fields as any)[key]
})
log.trace('[update]', 'Transaction updated', { id: self.id, fields: Object.keys(fields) })
},
pruneInputToken(inputToken: string) {
self.inputToken = inputToken.slice(0, 40)
log.trace('[pruneInputToken]', 'Transaction inputToken pruned in store', {id: self.id})
},
pruneOutputToken(outputToken: string) {
self.outputToken = outputToken.slice(0, 40)
log.trace('[pruneOutputToken]', 'Transaction outputToken pruned in store', {id: self.id})
},
}))
}))
export interface Transaction extends Instance<typeof TransactionModel> {}
/*export type Transaction = Partial<Instance<typeof TransactionModel>> & {
amount: number
fee: number
unit: MintUnit
type: TransactionType
data: string
mint: string
status: TransactionStatus
}*/
export interface TransactionSnapshotOut
extends SnapshotOut<typeof TransactionModel> {}
export interface TransactionSnapshotIn
extends SnapshotIn<typeof TransactionModel> {}
export interface TransactionSnapshotOut extends SnapshotOut<typeof TransactionModel> {}
export interface TransactionSnapshotIn extends SnapshotIn<typeof TransactionModel> {}
+16 -17
View File
@@ -460,12 +460,13 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
if(paymentOption === SendOption.PAY_CASHU_PAYMENT_REQUEST) {
if(decodedCashuPaymentRequest && decodedCashuPaymentRequest.id) {
// TODO make a single request
transaction.setPaymentId(decodedCashuPaymentRequest.id)
transaction.setPaymentRequest(encodedCashuPaymentRequest)
transaction.setProfile(JSON.stringify(contactToSendFrom))
transaction.setSentTo(contactToSendTo.nip05 || contactToSendTo.name) // payee
transaction.setSentFrom(contactToSendFrom.nip05 || contactToSendFrom.name) // payer
transaction.update({
paymentId: decodedCashuPaymentRequest.id,
paymentRequest: encodedCashuPaymentRequest,
profile: JSON.stringify(contactToSendFrom),
sentTo: contactToSendTo.nip05 || contactToSendTo.name, // payee
sentFrom: contactToSendFrom.nip05 || contactToSendFrom.name // payer
})
}
}
@@ -846,20 +847,18 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
updated[2].sentToRelays = relaysToShareTo
updated[2].sentEvent = sentEvent
transaction.setStatus( // status does not change, just add event and relay info to tx.data
TransactionStatus.PENDING,
JSON.stringify(updated)
)
// status does not change, just add event and relay info to tx.data
transaction.update({
status: TransactionStatus.PENDING,
data: JSON.stringify(updated)
})
}
if(contactToSendTo) {
transaction.setProfile(
JSON.stringify(contactToSendTo)
)
transaction.setSentTo(
contactToSendTo.nip05handle ?? contactToSendTo.name!
)
transaction.update({
profile: JSON.stringify(contactToSendTo),
sentTo: contactToSendTo.nip05handle ?? contactToSendTo.name!
})
}
} else {
+8 -8
View File
@@ -544,10 +544,10 @@ export const TopupScreen = observer(function TopupScreen({ route }: Props) {
updated[1].sentToRelays = relaysToShareTo
// status does not change, just add event and relay info to tx.data
transaction.setStatus(
TransactionStatus.PENDING,
JSON.stringify(updated),
)
transaction.update({
status: TransactionStatus.PENDING,
data: JSON.stringify(updated),
})
}
} else {
setInfo(translate('topup.relayMissingSentEvent'))
@@ -600,10 +600,10 @@ export const TopupScreen = observer(function TopupScreen({ route }: Props) {
error: result,
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(updated),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(updated),
})
setResultModalInfo({
status: TransactionStatus.ERROR,
+9 -9
View File
@@ -135,7 +135,7 @@ export const TranDetailScreen = observer(function TranDetailScreen({ route }: Pr
const onNoteSave = async function () {
try {
transaction!.setNote(note)
transaction.update({noteToSelf: note})
setIsNoteEditing(false)
} catch (e: any) {
handleError(e)
@@ -1658,7 +1658,7 @@ const TransferInfoBlock = function (props: {
mint?: Mint
colorScheme: 'dark' | 'light'
}) {
const {transaction, mint} = props
const {transaction, mint, isDataParsable} = props
const {proofsStore, transactionsStore} = useStores()
const navigation = useNavigation()
@@ -1701,6 +1701,7 @@ const TransferInfoBlock = function (props: {
log.trace('[onRevertPreparedTransfer]', {tId: transaction.id})
const pendingProofs = proofsStore.getByTransactionId(transaction.id!, true) // PREPARED should always pending
const transactionData = isDataParsable ? JSON.parse(transaction.data) : []
if(pendingProofs.length > 0) {
// remove it from pending proofs in the wallet
@@ -1711,17 +1712,16 @@ const TransferInfoBlock = function (props: {
const message = 'Ecash has been returned to spendable balance.'
const transactionDataUpdate = {
transactionData.push({
status: TransactionStatus.REVERTED,
message,
createdAt: new Date(),
}
})
await transactionsStore.updateStatuses(
[transaction.id!],
TransactionStatus.REVERTED,
JSON.stringify(transactionDataUpdate),
)
transaction.update({
status: TransactionStatus.REVERTED,
data: JSON.stringify(transactionData)
})
setResultModalInfo({status: TransactionStatus.REVERTED, message})
toggleResultModal()
+7 -3
View File
@@ -383,10 +383,14 @@ useEffect(() => {
const profile = contactsStore.findByLud16(lnurlPayParams.address)
if (profile) {
transaction.setSentTo(profile.nip05 || profile.name)
transaction.setProfile(JSON.stringify(profile))
transaction.update({
sentTo: profile.nip05 || profile.name,
profile: JSON.stringify(profile)
})
} else {
transaction.setSentTo(lnurlPayParams.address)
transaction.update({
sentTo: lnurlPayParams.address
})
}
}
+44 -425
View File
@@ -254,6 +254,48 @@ const getDatabaseVersion = function (db: QuickSQLiteConnection): {version: numbe
* Transactions
*/
const updateTransaction = function (id: number, fields: {[key:string]: any}): TransactionRecord {
const allowedColumns = ['amount','fee','unit','data','sentFrom','sentTo','profile','memo','paymentId','quote','paymentRequest','zapRequest','inputToken','outputToken','proof','balanceAfter','noteToSelf','tags','status','expiresAt'];
try {
// Filter keys against allowed columns to prevent SQL injection
const validKeys = Object.keys(fields).filter(key => allowedColumns.includes(key));
if (validKeys.length === 0) {
// No valid keys to update, return existing transaction
return getTransactionById(id);
}
// Build SET clauses and parameters
const setClauses = validKeys.map(key => `${key} = ?`);
const params = validKeys.map(key => fields[key]);
params.push(id); // Add id at the end for WHERE clause
const query = `
UPDATE transactions
SET ${setClauses.join(', ')}
WHERE id = ?
`;
const db = getInstance();
db.execute(query, params);
log.debug('[updateTransaction]', `Transaction updated in the database`, {id, fields: validKeys});
const updatedTx = getTransactionById(id);
return updatedTx as TransactionRecord;
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction in database',
e.message,
);
}
}
const getTransactions = function (limit: number, offset: number, onlyPending: boolean = false) {
let query: string = ''
try {
@@ -545,35 +587,6 @@ const addTransactionAsync = async function (tx: Transaction): Promise<Transactio
}
}
const updateStatus = function (
id: number,
status: TransactionStatus,
data: string,
) {
try {
const query = `
UPDATE transactions
SET status = ?, data = ?
WHERE id = ?
`
const params = [status, data, id]
const db = getInstance()
db.execute(query, params)
log.info('[updateStatus]', `Transaction status updated in the database`, {id, status})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction status in database',
e.message,
)
}
}
// This updates status and appends data to the existing transaction data
const updateStatusesAsync = async function (
@@ -639,411 +652,32 @@ const expireAllAfterRecovery = async function () {
return result
}
const updateBalanceAfter = function (
id: number,
balanceAfter: number,
) {
try {
const query = `
UPDATE transactions
SET balanceAfter = ?
WHERE id = ?
`
const params = [balanceAfter, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updateBalanceAfter]', 'Transaction balanceAfter updated', {id, balanceAfter})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction balanceAfter in database',
e.message,
)
}
}
const updatePaymentId = function (id: number, paymentId: string) {
try {
const query = `
UPDATE transactions
SET paymentId = ?
WHERE id = ?
`
const params = [paymentId, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updatePaymentId]', 'Transaction paymentId updated in the database', {id, paymentId})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction paymentId in the database',
e.message,
)
}
}
const updateQuote = function (id: number, quote: string) {
try {
const query = `
UPDATE transactions
SET quote = ?
WHERE id = ?
`
const params = [quote, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updatePaymentId]', 'Transaction quote updated in the database', {id, quote})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction quote in the database',
e.message,
)
}
}
const updateFee = function (id: number, fee: number) {
try {
const query = `
UPDATE transactions
SET fee = ?
WHERE id = ?
`
const params = [fee, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updateFee]', 'Transaction fee updated in the database', {id, fee})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction fee in the database',
e.message,
)
}
}
const updateReceivedAmount = function (id: number, amount: number) {
try {
const query = `
UPDATE transactions
SET amount = ?
WHERE id = ?
`
const params = [amount, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updateReceivedAmountAsync]', 'Transaction received amount updated in the database', {id, amount})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction received amount in database',
e.message,
)
}
}
const updateNote = function (id: number, note: string) {
try {
const query = `
UPDATE transactions
SET noteToSelf = ?
WHERE id = ?
`
const params = [note, id]
const db = getInstance()
db.executeAsync(query, params)
// DO NOT log to Sentry
log.trace('[updateNote]', 'Transaction note updated in the database', {id, note})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction note in database',
e.message,
)
}
}
const updateSentFrom = function (id: number, sentFrom: string) {
try {
const query = `
UPDATE transactions
SET sentFrom = ?
WHERE id = ?
`
const params = [sentFrom, id]
const db = getInstance()
db.executeAsync(query, params)
log.trace('[updateSentFrom]', 'Transaction sentFrom updated in the database', {id, sentFrom})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction sentFrom in database',
e.message,
)
}
}
const updateSentTo = function (id: number, sentTo: string) {
try {
const query = `
UPDATE transactions
SET sentTo = ?
WHERE id = ?
`
const params = [sentTo, id]
const db = getInstance()
db.execute(query, params)
log.trace('[updateSentToAsync]', 'Transaction sentTo updated in the database', {id, sentTo})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction sentTo in database',
e.message,
)
}
}
const updateProfile = function (id: number, profile: string) {
try {
const query = `
UPDATE transactions
SET profile = ?
WHERE id = ?
`
const params = [profile, id]
const db = getInstance()
db.execute(query, params)
log.trace('[updateProfile]', 'Transaction sentTo updated in the database', {id, profile})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction profile in database',
e.message,
)
}
}
const updateInputToken = function (id: number, inputToken: string) {
try {
const query = `
UPDATE transactions
SET inputToken = ?
WHERE id = ?
`
const params = [inputToken, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updateInputToken]', 'Transaction inputToken updated in the database', {id})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction inputToken in database',
e.message,
)
}
}
const updateOutputToken = function (id: number, outputToken: string) {
try {
const query = `
UPDATE transactions
SET outputToken = ?
WHERE id = ?
`
const params = [outputToken, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updateOutputToken]', 'Transaction outputToken updated in the database', {id, outputToken})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction outputToken in database',
e.message,
)
}
}
// proof of payment, e.g. preimage
const updateProof = function (id: number, proof: string) {
try {
const query = `
UPDATE transactions
SET proof = ?
WHERE id = ?
`
const params = [proof, id]
const db = getInstance()
db.execute(query, params)
log.debug('[updateProof]', 'Transaction proof updated in the database', {id, proof})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction proof in database',
e.message,
)
}
}
const updatePaymentRequest = function (id: number, paymentRequest: string) {
try {
const query = `
UPDATE transactions
SET paymentRequest = ?
WHERE id = ?
`
const params = [paymentRequest, id]
const db = getInstance()
db.execute(query, params)
log.trace('[updatePaymentRequest]', 'Transaction paymentRequest updated in the database', {id, paymentRequest})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction paymentRequest in database',
e.message,
)
}
}
const updateExpiresAt = function (id: number, expiresAt: Date) {
try {
const query = `
UPDATE transactions
SET expiresAt = ?
WHERE id = ?
`
const params = [expiresAt.toISOString(), id]
const db = getInstance()
db.execute(query, params)
log.trace('[updatePaymentRequest]', 'Transaction expiresAt updated in the database', {id, expiresAt})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction expiresAt in database',
e.message,
)
}
}
const updateZapRequest = function (id: number, zapRequest: string) {
try {
const query = `
UPDATE transactions
SET zapRequest = ?
WHERE id = ?
`
const params = [zapRequest, id]
const db = getInstance()
db.execute(query, params)
log.trace('[updateZapRequest]', 'Transaction zapRequest updated in the database', {id, zapRequest})
const updatedTx = getTransactionById(id as number)
return updatedTx as TransactionRecord
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not update transaction zapRequest in database',
e.message,
)
}
}
/* const cleanTransactionData = async function (transactionIds: number[]) {
try {
@@ -1395,24 +1029,9 @@ export const Database = {
getPendingTopups,
getPendingTopupsCount,
addTransactionAsync,
updateStatus,
updateTransaction,
expireAllAfterRecovery,
updateStatusesAsync,
updateBalanceAfter,
updateFee,
updatePaymentId,
updateQuote,
updateReceivedAmount,
updateNote,
updateSentFrom,
updateSentTo,
updateProfile,
updatePaymentRequest,
updateExpiresAt,
updateZapRequest,
updateInputToken,
updateOutputToken,
updateProof,
deleteTransactionsByStatus,
getPendingAmount,
addOrUpdateProof,
@@ -1424,4 +1043,4 @@ export const Database = {
getProofs,
getProofsByTransaction,
updateProofsToDefaultUnit
}
}
+10 -11
View File
@@ -96,12 +96,11 @@ export const cashuPaymentRequestTask = async function (
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.PENDING,
JSON.stringify(transactionData),
)
transaction.setPaymentId(cashuPrId)
transaction.update({
status: TransactionStatus.PENDING,
data: JSON.stringify(transactionData),
paymentId: cashuPrId
})
return {
taskFunction: CASHU_PAYMENT_REQUEST_TASK,
@@ -121,10 +120,10 @@ export const cashuPaymentRequestTask = async function (
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
log.error(e.name, e.message)
@@ -136,4 +135,4 @@ export const cashuPaymentRequestTask = async function (
error: WalletUtils.formatError(e),
} as TransactionTaskResult
}
}
}
+81 -92
View File
@@ -68,7 +68,7 @@ export const receiveTask = async function (
}
transaction = await transactionsStore.addTransaction(newTransaction)
transaction.setInputToken(encodedToken)
transaction.update({inputToken: encodedToken})
// Handle blocked mint
const isBlocked = mintsStore.isBlocked(mintToReceive)
@@ -76,13 +76,14 @@ export const receiveTask = async function (
if (isBlocked) {
transactionData.push({
status: TransactionStatus.BLOCKED,
message: 'Mint is blocked in your Settings, ecash has not been received.',
mintToReceive,
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.BLOCKED,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.BLOCKED,
data: JSON.stringify(transactionData),
})
return {
taskFunction: RECEIVE_TASK,
@@ -104,11 +105,6 @@ export const receiveTask = async function (
)
// Update tx amount if full amount was not received
if (receivedAmount !== amountToReceive) {
transaction.setReceivedAmount(receivedAmount)
}
// Finally, update completed transaction
transactionData.push({
status: TransactionStatus.COMPLETED,
@@ -118,19 +114,16 @@ export const receiveTask = async function (
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.COMPLETED,
JSON.stringify(transactionData),
)
transaction.setOutputToken(outputToken)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
if(swapFeePaid > 0) {
transaction.setFee(swapFeePaid)
}
transaction.update({
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
outputToken,
balanceAfter,
...(receivedAmount !== amountToReceive && {receivedAmount}),
...(swapFeePaid > 0 && {fee: swapFeePaid})
})
return {
taskFunction: RECEIVE_TASK,
@@ -150,10 +143,10 @@ export const receiveTask = async function (
errorToken: e.params?.errorToken || undefined
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
log.error(e.name, e.message)
@@ -210,21 +203,27 @@ export const receiveOfflinePrepareTask = async function (
}
transaction = await transactionsStore.addTransaction(newTransaction)
transaction.setInputToken(encodedToken)
transaction.update({inputToken: encodedToken})
// Handle blocked mint
const isBlocked = mintsStore.isBlocked(mintToReceive)
if (isBlocked) {
const blockedTransaction = transaction.setStatus(
TransactionStatus.BLOCKED,
JSON.stringify(transactionData),
)
transactionData.push({
status: TransactionStatus.BLOCKED,
mintToReceive,
createdAt: new Date()
})
transaction.update({
status: TransactionStatus.BLOCKED,
data: JSON.stringify(transactionData),
})
return {
taskFunction: RECEIVE_OFFLINE_PREPARE_TASK,
mintUrl: mintToReceive,
transaction: blockedTransaction,
transaction,
message: `The mint ${mintToReceive} is blocked. You can unblock it in Settings.`,
} as unknown as TransactionTaskResult
}
@@ -235,10 +234,10 @@ export const receiveOfflinePrepareTask = async function (
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.PREPARED_OFFLINE,
JSON.stringify(transactionData),
)
transaction.update( {
status: TransactionStatus.PREPARED_OFFLINE,
data: JSON.stringify(transactionData),
})
return {
taskFunction: RECEIVE_OFFLINE_PREPARE_TASK,
@@ -254,10 +253,10 @@ export const receiveOfflinePrepareTask = async function (
error: WalletUtils.formatError(e),
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData),
})
}
log.error(e.name, e.message)
@@ -305,10 +304,16 @@ export const receiveOfflineCompleteTask = async function (
const isBlocked = mintsStore.isBlocked(mintToReceive)
if (isBlocked) {
transaction.setStatus(
TransactionStatus.BLOCKED,
JSON.stringify(transactionData),
)
transactionData.push({
status: TransactionStatus.BLOCKED,
mintToReceive,
createdAt: new Date()
})
transaction.update({
status: TransactionStatus.BLOCKED,
data: JSON.stringify(transactionData),
})
return {
taskFunction: RECEIVE_OFFLINE_COMPLETE_TASK,
@@ -329,11 +334,6 @@ export const receiveOfflineCompleteTask = async function (
transaction.id
)
// Update tx amount if full amount was not received
if (receivedAmount !== transaction.amount) {
transaction.setReceivedAmount(receivedAmount)
}
// Finally, update completed transaction
transactionData.push({
status: TransactionStatus.COMPLETED,
@@ -343,19 +343,16 @@ export const receiveOfflineCompleteTask = async function (
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.COMPLETED,
JSON.stringify(transactionData),
)
transaction.setOutputToken(outputToken)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
if(swapFeePaid > 0) {
transaction.setFee(swapFeePaid)
}
transaction.update({
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
outputToken,
balanceAfter,
...(receivedAmount !== transaction.amount && {receivedAmount}),
...(swapFeePaid > 0 && {fee: swapFeePaid})
})
return {
taskFunction: RECEIVE_OFFLINE_COMPLETE_TASK,
@@ -375,10 +372,10 @@ export const receiveOfflineCompleteTask = async function (
error: WalletUtils.formatError(e),
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
return {
@@ -450,10 +447,10 @@ export const receiveByCashuPaymentRequestTask = async function (
message: 'Mint is blocked in your Settings, ecash has not been received.',
})
transaction.setStatus(
TransactionStatus.BLOCKED,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.BLOCKED,
data: JSON.stringify(transactionData),
})
return {
taskFunction: RECEIVE_BY_CASHU_PAYMENT_REQUEST_TASK,
@@ -476,11 +473,6 @@ export const receiveByCashuPaymentRequestTask = async function (
)
// Update tx amount if full amount was not received
if (receivedAmount !== amountToReceive) {
transaction.setReceivedAmount(receivedAmount)
}
// Finally, update completed transaction
transactionData.push({
status: TransactionStatus.COMPLETED,
@@ -490,19 +482,16 @@ export const receiveByCashuPaymentRequestTask = async function (
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.COMPLETED,
JSON.stringify(transactionData),
)
transaction.setOutputToken(outputToken)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
if(swapFeePaid > 0) {
transaction.setFee(swapFeePaid)
}
transaction.update({
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
outputToken,
balanceAfter,
...(receivedAmount !== amountToReceive && {receivedAmount}),
...(swapFeePaid > 0 && {fee: swapFeePaid})
})
return {
taskFunction: RECEIVE_BY_CASHU_PAYMENT_REQUEST_TASK,
@@ -522,10 +511,10 @@ export const receiveByCashuPaymentRequestTask = async function (
errorToken: e.params?.errorToken || undefined
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
log.error(e.name, e.message)
@@ -623,4 +612,4 @@ export const receiveSync = async function (
throw new AppError(Err.WALLET_ERROR, e.message, e.stack.slice(0, 200))
}
}
}
}
+13 -16
View File
@@ -87,18 +87,15 @@ try {
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.REVERTED,
JSON.stringify(transactionData),
)
transaction.setOutputToken(outputToken)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
if(mintFeePaid > 0) {
transaction.setFee(mintFeePaid)
}
transaction.update({
status: TransactionStatus.REVERTED,
data: JSON.stringify(transactionData),
outputToken,
balanceAfter,
...(mintFeePaid > 0 && {fee: mintFeePaid})
})
return {
taskFunction: REVERT_TASK,
@@ -116,10 +113,10 @@ try {
errorToken: e.params?.errorToken || undefined
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
log.error(e.name, e.message)
@@ -132,4 +129,4 @@ try {
error: WalletUtils.formatError(e),
} as TransactionTaskResult
}
}
}
+16 -20
View File
@@ -106,11 +106,6 @@ export const sendTask = async function (
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.PREPARED,
JSON.stringify(transactionData),
)
// Create sendable encoded token
if (!memo || memo === '') {
memo = 'Sent from Minibits'
@@ -123,24 +118,25 @@ export const sendTask = async function (
memo,
})
transaction.setOutputToken(outputToken)
transaction.update({
status: TransactionStatus.PREPARED,
data: JSON.stringify(transactionData),
outputToken
})
transactionData.push({
status: TransactionStatus.PENDING,
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.PENDING,
JSON.stringify(transactionData),
)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
if(swapFeePaid > 0) {
transaction.setFee(swapFeePaid)
}
transaction.update({
status: TransactionStatus.PENDING,
data: JSON.stringify(transactionData),
balanceAfter,
...(swapFeePaid > 0 && {fee: swapFeePaid})
})
log.trace('[send] totalBalance after', balanceAfter)
@@ -204,10 +200,10 @@ export const sendTask = async function (
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
return {
@@ -588,4 +584,4 @@ const getInactiveKeysetIds = function(mint: Mint) {
}
return []
}
}
+22 -17
View File
@@ -101,15 +101,18 @@ export const topupTask = async function (
// contactToSendTo is to whom to send the request
const contactTo = isStateTreeNode(contactToSendTo) ? getSnapshot(contactToSendTo) : contactToSendTo
// TODO make single insert
transaction.setQuote(mintQuote)
transaction.setPaymentId(paymentHash)
transaction.setPaymentRequest(encodedInvoice)
transaction.setExpiresAt(addSeconds(new Date(timestamp * 1000), expiry))
// SATS flow in reverse compared with payment request
transaction.setSentFrom(contactTo.nip05 || contactTo.name)
transaction.setSentTo(walletProfileStore.nip05)
// Bulk update quote, paymentId, paymentRequest, expiresAt, sentFrom, sentTo
const expiresAtDate = addSeconds(new Date(timestamp * 1000), expiry)
const sentFromValue = contactTo?.nip05 || contactTo?.name || ''
const sentToValue = walletProfileStore.nip05 || ''
transaction.update({
quote: mintQuote,
paymentId: paymentHash,
paymentRequest: encodedInvoice,
expiresAt: expiresAtDate,
sentFrom: sentFromValue,
sentTo: sentToValue
})
log.trace('[topupTask] invoice', {amount, paymentHash, expiry, timestamp})
@@ -118,10 +121,11 @@ export const topupTask = async function (
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.PENDING,
JSON.stringify(transactionData),
)
// Update status and data in one call
transaction.update({
status: TransactionStatus.PENDING,
data: JSON.stringify(transactionData)
})
if(!nwcEvent) {
const wsMint = new CashuMint(mintUrl)
@@ -177,10 +181,11 @@ export const topupTask = async function (
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
// Update status and data on error
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
log.error(e.name, e.message)
+39 -35
View File
@@ -85,8 +85,8 @@ export const transferTask = async function (
const transactionId = transaction.id
const paymentHash = LightningUtils.getInvoiceData(LightningUtils.decodeInvoice(encodedInvoice)).payment_hash
transaction.setPaymentId(paymentHash)
transaction.setQuote(meltQuote.quote)
// Replace individual setters with a single update
transaction.update({ paymentId: paymentHash, quote: meltQuote.quote })
if (amountToTransfer + meltQuote.fee_reserve > mintBalanceToTransferFrom.balances[unit]!) {
throw new AppError(
@@ -162,7 +162,7 @@ export const transferTask = async function (
unit,
})
// Update transaction status
// Update transaction status and inputToken in one call
transactionData.push({
status: TransactionStatus.PREPARED,
proofsToMeltFromAmount,
@@ -171,18 +171,17 @@ export const transferTask = async function (
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.PREPARED,
JSON.stringify(transactionData),
)
const inputToken = getEncodedToken({
mint: mintUrl,
proofs: proofsToMeltFrom,
unit
})
transaction.setInputToken(inputToken)
transaction.update({
status: TransactionStatus.PREPARED,
data: JSON.stringify(transactionData),
inputToken,
})
try {
meltResponse = await walletStore.payLightningMelt(
@@ -217,16 +216,18 @@ export const transferTask = async function (
// Spend pending proofs that were used to settle the lightning invoice
proofsStore.removeProofs(proofsToMeltFrom as Proof[], true, false)
// Save preimage asap
if(meltResponse.quote.payment_preimage) {
transaction.setProof(meltResponse.quote.payment_preimage)
}
// compute fees and change
let totalFeePaid = proofsToMeltFromAmount - amountToTransfer
let lightningFeePaid = totalFeePaid - meltFeeReserve
let meltFeePaid = meltFeeReserve
let returnedAmount = CashuUtils.getProofsAmount(meltResponse.change)
let outputToken: string | undefined
if(meltResponse.quote.payment_preimage) {
// include proof in update payload
}
if(meltResponse.change.length > 0) {
WalletUtils.addCashuProofs(
@@ -239,40 +240,43 @@ export const transferTask = async function (
}
)
const outputToken = getEncodedToken({
outputToken = getEncodedToken({
mint: mintUrl,
proofs: meltResponse.change,
unit,
})
transaction.setOutputToken(outputToken)
totalFeePaid = totalFeePaid - returnedAmount
lightningFeePaid = totalFeePaid - meltFeeReserve
}
// Save final fee in db
if(totalFeePaid !== transaction.fee) {
transaction.setFee(totalFeePaid)
}
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
// Update transaction status
transactionData.push({
// build consolidated update payload
const completedDataItem: TransactionData = {
status: TransactionStatus.COMPLETED,
lightningFeePaid,
meltFeePaid,
returnedAmount,
preimage: meltResponse.quote.payment_preimage,
createdAt: new Date(),
})
transaction.setStatus(
TransactionStatus.COMPLETED,
JSON.stringify(transactionData),
)
}
transactionData.push(completedDataItem)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
const updatePayload: any = {
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
fee: totalFeePaid,
balanceAfter,
}
if (outputToken) {
updatePayload.outputToken = outputToken
}
if (meltResponse.quote.payment_preimage) {
updatePayload.proof = meltResponse.quote.payment_preimage
}
transaction.update(updatePayload)
return {
taskFunction: TRANSFER_TASK,
@@ -405,10 +409,10 @@ export const transferTask = async function (
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData),
})
}
return taskResult
+145 -152
View File
@@ -1172,6 +1172,7 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
for(const inFlight of counter.inFlightRequests) {
const transaction = transactionsStore.findById(inFlight.transactionId)
const transactionData = JSON.parse(transaction.data)
if(!transaction) {
counter.removeInFlightRequest(inFlight.transactionId)
@@ -1222,28 +1223,27 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
// Update tx amount if full amount was not received
if (receivedAmount !== transaction.amount) {
transaction.setReceivedAmount(receivedAmount)
transaction.update({amount: receivedAmount})
}
await transactionsStore.updateStatuses(
[transaction.id],
TransactionStatus.COMPLETED,
JSON.stringify({
status: TransactionStatus.COMPLETED,
receivedAmount,
swapFeePaid,
unit,
createdAt: new Date(),
}),
)
transaction.setOutputToken(outputToken)
transactionData.push({
status: TransactionStatus.COMPLETED,
receivedAmount,
swapFeePaid,
unit,
createdAt: new Date(),
})
transaction.update({
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
})
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
transaction.update({balanceAfter, outputToken})
if(swapFeePaid > 0) {
transaction.setFee(swapFeePaid)
transaction.update({fee: swapFeePaid})
}
break
@@ -1310,24 +1310,23 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
proofs: proofsToSend,
unit,
})
transaction.setOutputToken(outputToken)
// Finally, update completed transaction
await transactionsStore.updateStatuses(
[transaction.id],
TransactionStatus.PENDING,
JSON.stringify({
status: TransactionStatus.PENDING,
createdAt: new Date(),
})
)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
transactionData.push({
status: TransactionStatus.PENDING,
createdAt: new Date(),
})
transaction.update({
status: TransactionStatus.PENDING,
data: JSON.stringify(transactionData),
outputToken,
balanceAfter
})
if(swapFeePaid > 0) {
transaction.setFee(swapFeePaid)
transaction.update({fee: swapFeePaid})
}
break
@@ -1370,20 +1369,21 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
)
}
stopPolling(`handlePendingTopupPoller-${transaction.paymentId}`)
await transactionsStore.updateStatuses(
[transaction.id],
TransactionStatus.COMPLETED,
JSON.stringify({
status: TransactionStatus.COMPLETED,
createdAt: new Date(),
})
)
// Update tx with current total balance of topup unit/currency
stopPolling(`handlePendingTopupPoller-${transaction.paymentId}`)
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
transactionData.push({
status: TransactionStatus.COMPLETED,
createdAt: new Date(),
})
transaction.update({
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
balanceAfter
})
break
} catch(e: any) {
@@ -1412,7 +1412,7 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
// Save preimage asap
if(quote.payment_preimage) {
transaction.setProof(quote.payment_preimage)
transaction.update({proof: quote.payment_preimage})
}
const proofsToMeltFromAmount = CashuUtils.getProofsAmount(inFlight.request.proofsToSend)
@@ -1447,29 +1447,31 @@ const handleInFlightByMintTask = async function (mint: Mint): Promise<WalletTask
unit,
})
transaction.setOutputToken(outputToken)
transaction.update({outputToken})
totalFeePaid = totalFeePaid - returnedAmount
}
// Save final fee in db
if(totalFeePaid !== transaction.fee) {
transaction.setFee(totalFeePaid)
}
await transactionsStore.updateStatuses(
[transaction.id],
TransactionStatus.COMPLETED,
JSON.stringify({
status: TransactionStatus.COMPLETED,
returnedAmount,
preimage: quote.payment_preimage,
createdAt: new Date(),
})
)
transaction.update({fee: totalFeePaid})
}
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
transactionData.push({
status: TransactionStatus.COMPLETED,
returnedAmount,
preimage: quote.payment_preimage,
createdAt: new Date(),
})
transaction.update({
status: TransactionStatus.COMPLETED,
data: JSON.stringify(transactionData),
balanceAfter
})
break
} catch(e: any) {
@@ -1556,6 +1558,7 @@ const handlePendingTopupTask = async function (params: {transaction: Transaction
expiresAt
} = transaction
const transactionData = JSON.parse(transaction.data)
const mintInstance = mintsStore.findByUrl(mintUrl as string)
try {
@@ -1575,17 +1578,16 @@ const handlePendingTopupTask = async function (params: {transaction: Transaction
// expire related tx - but only if it has not been completed before this check
if(transaction.status !== TransactionStatus.COMPLETED) {
const transactionDataUpdate = {
transactionData.push({
status: TransactionStatus.EXPIRED,
message: 'Invoice expired',
createdAt: new Date(),
}
})
await transactionsStore.updateStatuses(
[transactionId],
TransactionStatus.EXPIRED,
JSON.stringify(transactionDataUpdate),
)
transaction.update({
status: TransactionStatus.EXPIRED,
data: JSON.stringify(transactionData)
})
}
stopPolling(`handlePendingTopupPoller-${paymentHash}`)
@@ -1654,24 +1656,21 @@ const handlePendingTopupTask = async function (params: {transaction: Transaction
)
stopPolling(`handlePendingTopupPoller-${paymentHash}`)
const currencyCode = getCurrency(unit).code
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
// update related tx
const transactionDataUpdate = {
status: TransactionStatus.COMPLETED,
transactionData.push({
status: TransactionStatus.COMPLETED,
createdAt: new Date(),
}
// await for final status
await transactionsStore.updateStatuses(
[transactionId],
TransactionStatus.COMPLETED,
JSON.stringify(transactionDataUpdate),
)
// Update tx with current total balance of topup unit/currency
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
})
transaction.update({
status: TransactionStatus.COMPLETED,
balanceAfter,
data: JSON.stringify(transactionData)
})
_sendTopupNotification(amount, unit)
@@ -1776,7 +1775,8 @@ const recoverMintQuote = async function (params: {mintUrl: string, mintQuote: st
}
// store tx in db and in the model
const transaction = await transactionsStore.addTransaction(newTransaction)
const transactionId = transaction.id
const transactionId = transaction.id
const transactioData = JSON.parse(transaction.data)
let proofs: CashuProof[] = []
@@ -1821,25 +1821,18 @@ const recoverMintQuote = async function (params: {mintUrl: string, mintQuote: st
}
)
const currencyCode = getCurrency(unit).code
// update related tx
const transactionDataUpdate = {
status: TransactionStatus.RECOVERED,
createdAt: new Date(),
}
// await for final status
await transactionsStore.updateStatuses(
[transactionId],
TransactionStatus.RECOVERED,
JSON.stringify(transactionDataUpdate),
)
// Update tx with current total balance of topup unit/currency
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
transaction.setBalanceAfter(balanceAfter)
transactionData.push({
status: TransactionStatus.RECOVERED,
createdAt: new Date(),
})
transaction.update({
status: TransactionStatus.RECOVERED,
balanceAfter,
data: JSON.stringify(transactionData)
})
return { recoveredAmount }
/*
@@ -1906,18 +1899,17 @@ const recoverMeltQuoteChange = async function (params: {mintUrl: string, meltQuo
transaction = transactionsStore.findByQuote(meltQuote)
transactionId = transaction?.id
const transactionData: TransactionData[] = transaction ? JSON.parse(transaction.data) : []
// Older transactions might not have quote set
if(!transaction) {
const transactionData: TransactionData[] = [
{
transactionData.push({
status: TransactionStatus.DRAFT,
amountToRecover,
unit,
meltQuoteToRecover: quote,
createdAt: new Date(),
}
]
})
const newTransaction = {
type: TransactionType.RECEIVE,
@@ -1931,7 +1923,7 @@ const recoverMeltQuoteChange = async function (params: {mintUrl: string, meltQuo
}
// store tx in db and in the model
const transaction = await transactionsStore.addTransaction(newTransaction)
transaction.setQuote(meltQuote)
transaction.update({quote: meltQuote})
transactionId = transaction.id
}
@@ -1973,32 +1965,28 @@ const recoverMeltQuoteChange = async function (params: {mintUrl: string, meltQuo
)
if(amountToRecover !== recoveredAmount) {
transaction.setReceivedAmount(recoveredAmount)
transaction.update({amount: recoveredAmount})
}
// update related tx
const transactionDataUpdate = {
status: TransactionStatus.RECOVERED,
recoveredAmount,
createdAt: new Date(),
}
// await for final status
await transactionsStore.updateStatuses(
[transactionId],
TransactionStatus.RECOVERED,
JSON.stringify(transactionDataUpdate),
)
// Update tx with current total balance of topup unit/currency
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance!
const outputToken = getEncodedToken({
mint: mintUrl,
proofs: returnedProofs,
unit,
})
transaction.setBalanceAfter(balanceAfter)
transaction.setOutputToken(outputToken)
transactionData.push({
status: TransactionStatus.RECOVERED,
recoveredAmount,
createdAt: new Date(),
})
transaction.update({
status: TransactionStatus.RECOVERED,
balanceAfter,
outputToken,
data: JSON.stringify(transactionData)
})
return { recoveredAmount }
@@ -2011,10 +1999,10 @@ const recoverMeltQuoteChange = async function (params: {mintUrl: string, meltQuo
createdAt: new Date()
})
transaction.setStatus(
TransactionStatus.ERROR,
JSON.stringify(transactionData),
)
transaction.update({
status: TransactionStatus.ERROR,
data: JSON.stringify(transactionData)
})
}
/*
* UNKNOWN
@@ -2107,15 +2095,17 @@ const handleClaimTask = async function (params: {
if(transaction) {
if (zapSenderProfile) {
transaction.setProfile(zapSenderProfile as string)
let sentFrom: string = ''
try {
const profile: NostrProfile = JSON.parse(zapSenderProfile)
transaction.setSentFrom(profile.nip05 ?? profile.name)
sentFrom = profile.nip05 ?? profile.name
} catch(e: any) {}
transaction.update({profile: zapSenderProfile, sentFrom})
}
if (zapRequest) {
transaction.setZapRequest(zapRequest as string)
transaction.update({zapRequest})
}
}
}
@@ -2363,14 +2353,12 @@ const handleReceivedEventTask = async function (encryptedEvent: NostrEvent): Pro
// store contact or zapseder in tx details
if(transaction && sentFrom) {
if (contactFrom) {
transaction.setProfile(JSON.stringify(contactFrom))
transaction.setSentFrom(sentFrom)
if (contactFrom) {
transaction.update({profile: JSON.stringify(contactFrom), sentFrom})
}
if (zapSenderProfile) {
transaction.setProfile(JSON.stringify(zapSenderProfile))
transaction.setSentFrom(sentFrom)
transaction.update({profile: JSON.stringify(zapSenderProfile), sentFrom})
}
const isZap = zapSenderProfile ? true : false
@@ -2452,13 +2440,15 @@ const handleReceivedEventTask = async function (encryptedEvent: NostrEvent): Pro
}
const transaction = await transactionsStore.addTransaction(newTransaction)
// TODO make single insert
transaction.setPaymentId(paymentHash)
transaction.setPaymentRequest(incoming.encoded)
transaction.setExpiresAt(addSeconds(new Date(timestamp * 1000), expiry))
transaction.setProfile(JSON.stringify(contactFrom))
transaction.setSentTo(contactFrom.nip05 || contactFrom.name) // payee
transaction.setSentFrom(contactTo.nip05 || contactTo.name) // payer
transaction.update({
paymentId: paymentHash,
paymentRequest: incoming.encoded,
expiresAt: addSeconds(new Date(timestamp * 1000), expiry),
profile: JSON.stringify(contactFrom),
sentTo: contactFrom.nip05 ?? contactFrom.name, // payee
sentFrom: contactTo.nip05 ?? contactTo.name // payer
})
_sendIncomingInvoiceNotification(amount, 'sat', contactFrom)
@@ -2542,11 +2532,13 @@ const handleReceivedEventTask = async function (encryptedEvent: NostrEvent): Pro
const transaction = await transactionsStore.addTransaction(newTransaction)
// TODO make single insert
transaction.setPaymentId(id)
transaction.setPaymentRequest(incoming.encoded)
transaction.setProfile(JSON.stringify(contactFrom))
transaction.setSentTo(contactFrom.nip05 || contactFrom.name) // payee
transaction.setSentFrom(contactTo.nip05 || contactTo.name) // payer
transaction.update({
paymentId: id,
paymentRequest: incoming.encoded,
profile: JSON.stringify(contactFrom),
sentTo: contactFrom.nip05 ?? contactFrom.name, // payee
sentFrom: contactTo.nip05 ?? contactTo.name // payer
})
_sendIncomingInvoiceNotification(amount, unit as MintUnit, contactFrom)
@@ -2573,9 +2565,10 @@ const handleReceivedEventTask = async function (encryptedEvent: NostrEvent): Pro
// store contact or zapseder in tx details
if(transaction && sentFrom) {
if (contactFrom) {
transaction.setProfile(JSON.stringify(contactFrom))
transaction.setSentFrom(sentFrom)
transaction.update({profile: JSON.stringify(contactFrom), sentFrom})
}
transaction.update({paymentId: decoded.id})
// We do it defensively only after cash is received
// and asynchronously so we speed up queue