diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 672e07b12..f30e779e5 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -54,19 +54,23 @@ export class BalanceResolver { }, }) + // The decay is always calculated on the last booked transaction + const calculatedDecay = calculateDecay( + lastTransaction.balance, + lastTransaction.balanceDate, + now, + ) + + // The final balance is reduced by the link amount withheld const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount } = context.sumHoldAvailableAmount ? { sumHoldAvailableAmount: context.sumHoldAvailableAmount } : await transactionLinkRepository.summary(user.id, now) - const calculatedDecay = calculateDecay( - lastTransaction.balance.minus(sumHoldAvailableAmount.toString()), - lastTransaction.balanceDate, - now, - ) - return new Balance({ - balance: calculatedDecay.balance.toDecimalPlaces(2, Decimal.ROUND_DOWN), // round towards zero + balance: calculatedDecay.balance + .minus(sumHoldAvailableAmount.toString()) + .toDecimalPlaces(2, Decimal.ROUND_DOWN), // round towards zero decay: calculatedDecay.decay.toDecimalPlaces(2, Decimal.ROUND_FLOOR), // round towards - infinity lastBookedBalance: lastTransaction.balance.toDecimalPlaces(2, Decimal.ROUND_DOWN), balanceGDT, diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 461a70a00..aa1bba639 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -57,7 +57,12 @@ export const executeTransaction = async ( // validate amount const receivedCallDate = new Date() - const sendBalance = await calculateBalance(sender.id, amount.mul(-1), receivedCallDate) + const sendBalance = await calculateBalance( + sender.id, + amount.mul(-1), + receivedCallDate, + transactionLink, + ) if (!sendBalance) { throw new Error("user hasn't enough GDD or amount is < 0") } @@ -198,12 +203,15 @@ export class TransactionResolver { // decay & link transactions if (currentPage === 1 && order === Order.DESC) { + // The virtual decay is always on the booked amount, not including the generated, not yet booked links, + // since the decay is substantially different when the amount is less transactions.push( virtualDecayTransaction( - lastTransaction.balance.minus(sumHoldAvailableAmount.toString()), + lastTransaction.balance, lastTransaction.balanceDate, now, self, + sumHoldAvailableAmount, ), ) // virtual transaction for pending transaction-links sum diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index 95e1bf699..8d1c90ca4 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -4,6 +4,7 @@ import { Transaction } from '@entity/Transaction' import { Decay } from '@model/Decay' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLinkRepository } from '@repository/TransactionLink' +import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' function isStringBoolean(value: string): boolean { const lowerValue = value.toLowerCase() @@ -21,6 +22,7 @@ async function calculateBalance( userId: number, amount: Decimal, time: Date, + transactionLink?: dbTransactionLink | null, ): Promise<{ balance: Decimal; decay: Decay; lastTransactionId: number } | null> { const lastTransaction = await Transaction.findOne({ userId }, { order: { balanceDate: 'DESC' } }) if (!lastTransaction) return null @@ -32,7 +34,13 @@ async function calculateBalance( const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount } = await transactionLinkRepository.summary(userId, time) - if (balance.minus(sumHoldAvailableAmount.toString()).lessThan(0)) { + // If we want to redeem a link we need to make sure that the link amount is not considered as blocked + // else we cannot redeem links which are more or equal to half of what an account actually owns + const releasedLinkAmount = transactionLink ? transactionLink.holdAvailableAmount : new Decimal(0) + + if ( + balance.minus(sumHoldAvailableAmount.toString()).plus(releasedLinkAmount.toString()).lessThan(0) + ) { return null } return { balance, lastTransactionId: lastTransaction.id, decay } diff --git a/backend/src/util/virtualTransactions.ts b/backend/src/util/virtualTransactions.ts index e4b9eec1f..ff1b7548e 100644 --- a/backend/src/util/virtualTransactions.ts +++ b/backend/src/util/virtualTransactions.ts @@ -59,6 +59,7 @@ const virtualDecayTransaction = ( balanceDate: Date, time: Date = new Date(), user: User, + holdAvailabeAmount: Decimal, ): Transaction => { const decay = calculateDecay(balance, balanceDate, time) // const balance = decay.balance.minus(lastTransaction.balance) @@ -67,10 +68,12 @@ const virtualDecayTransaction = ( userId: -1, previous: -1, typeId: TransactionTypeId.DECAY, - amount: decay.decay ? decay.decay : new Decimal(0), // new Decimal(0), // this kinda is wrong, but helps with the frontend query - balance: decay.balance, + amount: decay.decay ? decay.decay.toDecimalPlaces(2, Decimal.ROUND_FLOOR) : new Decimal(0), // new Decimal(0), // this kinda is wrong, but helps with the frontend query + balance: decay.balance + .minus(holdAvailabeAmount.toString()) + .toDecimalPlaces(2, Decimal.ROUND_DOWN), balanceDate: time, - decay: decay.decay ? decay.decay : new Decimal(0), + decay: decay.decay ? decay.decay.toDecimalPlaces(2, Decimal.ROUND_FLOOR) : new Decimal(0), decayStart: decay.start, memo: '', creationDate: null,