diff --git a/backend/src/federation/client/1_0/SendCoinsClient.ts b/backend/src/federation/client/1_0/SendCoinsClient.ts index e8bd5c578..3b3bf4f2c 100644 --- a/backend/src/federation/client/1_0/SendCoinsClient.ts +++ b/backend/src/federation/client/1_0/SendCoinsClient.ts @@ -64,7 +64,7 @@ export class SendCoinsClient { const { data } = await this.client.rawRequest(revertSendCoins, { args }) logger.debug(`X-Com: SendCoinsClient: after revertSendCoins: data=`, data) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!data?.revertSendCoins?.revertSendCoins) { + if (!data?.revertSendCoins) { logger.warn('X-Com: revertSendCoins without response data from endpoint', this.endpoint) return false } @@ -89,7 +89,7 @@ export class SendCoinsClient { const { data } = await this.client.rawRequest(settleSendCoins, { args }) logger.debug(`X-Com: SendCoinsClient: after settleSendCoins: data=`, data) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!data?.settleSendCoins?.acknowledged) { + if (!data?.settleSendCoins) { logger.warn( 'X-Com: SendCoinsClient: settleSendCoins without response data from endpoint', this.endpoint, @@ -116,7 +116,7 @@ export class SendCoinsClient { const { data } = await this.client.rawRequest(revertSettledSendCoins, { args }) logger.debug(`X-Com: SendCoinsClient: after revertSettledSendCoins: data=`, data) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!data?.revertSettledSendCoins?.acknowledged) { + if (!data?.revertSettledSendCoins) { logger.warn( 'X-Com: SendCoinsClient: revertSettledSendCoins without response data from endpoint', this.endpoint, diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 0c35ed401..73f998b43 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -209,158 +209,6 @@ export const executeTransaction = async ( return true } -/* -export const executeCrossTransaction = async ( - amount: Decimal, - memo: string, - sender: dbUser, - recipientIdentifier: string, - transactionLink?: dbTransactionLink | null, -): Promise => { - // acquire lock - const releaseLock = await TRANSACTIONS_LOCK.acquire() - try { - logger.info('executeCrossTransaction', amount, memo, sender, recipientIdentifier) - - if (sender.id === recipient.id) { - throw new LogError('Sender and Recipient are the same', sender.id) - } - - if (memo.length < MEMO_MIN_CHARS) { - throw new LogError('Memo text is too short', memo.length) - } - - if (memo.length > MEMO_MAX_CHARS) { - throw new LogError('Memo text is too long', memo.length) - } - - // validate amount - const receivedCallDate = new Date() - const sendBalance = await calculateBalance( - sender.id, - amount.mul(-1), - receivedCallDate, - transactionLink, - ) - logger.debug(`calculated Balance=${sendBalance}`) - if (!sendBalance) { - throw new LogError('User has not enough GDD or amount is < 0', sendBalance) - } - - const queryRunner = getConnection().createQueryRunner() - await queryRunner.connect() - await queryRunner.startTransaction('REPEATABLE READ') - logger.debug(`open Transaction to write...`) - try { - // transaction - const transactionSend = new dbTransaction() - transactionSend.typeId = TransactionTypeId.SEND - transactionSend.memo = memo - transactionSend.userId = sender.id - transactionSend.userGradidoID = sender.gradidoID - transactionSend.userName = fullName(sender.firstName, sender.lastName) - transactionSend.linkedUserId = recipient.id - transactionSend.linkedUserGradidoID = recipient.gradidoID - transactionSend.linkedUserName = fullName(recipient.firstName, recipient.lastName) - transactionSend.amount = amount.mul(-1) - transactionSend.balance = sendBalance.balance - transactionSend.balanceDate = receivedCallDate - transactionSend.decay = sendBalance.decay.decay - transactionSend.decayStart = sendBalance.decay.start - transactionSend.previous = sendBalance.lastTransactionId - transactionSend.transactionLinkId = transactionLink ? transactionLink.id : null - await queryRunner.manager.insert(dbTransaction, transactionSend) - - logger.debug(`sendTransaction inserted: ${dbTransaction}`) - - const transactionReceive = new dbTransaction() - transactionReceive.typeId = TransactionTypeId.RECEIVE - transactionReceive.memo = memo - transactionReceive.userId = recipient.id - transactionReceive.userGradidoID = recipient.gradidoID - transactionReceive.userName = fullName(recipient.firstName, recipient.lastName) - transactionReceive.linkedUserId = sender.id - transactionReceive.linkedUserGradidoID = sender.gradidoID - transactionReceive.linkedUserName = fullName(sender.firstName, sender.lastName) - transactionReceive.amount = amount - const receiveBalance = await calculateBalance(recipient.id, amount, receivedCallDate) - transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount - transactionReceive.balanceDate = receivedCallDate - transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0) - transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null - transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null - transactionReceive.linkedTransactionId = transactionSend.id - transactionReceive.transactionLinkId = transactionLink ? transactionLink.id : null - await queryRunner.manager.insert(dbTransaction, transactionReceive) - logger.debug(`receive Transaction inserted: ${dbTransaction}`) - - // Save linked transaction id for send - transactionSend.linkedTransactionId = transactionReceive.id - await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend) - logger.debug('send Transaction updated', transactionSend) - - if (transactionLink) { - logger.info('transactionLink', transactionLink) - transactionLink.redeemedAt = receivedCallDate - transactionLink.redeemedBy = recipient.id - await queryRunner.manager.update( - dbTransactionLink, - { id: transactionLink.id }, - transactionLink, - ) - } - - await queryRunner.commitTransaction() - logger.info(`commit Transaction successful...`) - - await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount) - - await EVENT_TRANSACTION_RECEIVE( - recipient, - sender, - transactionReceive, - transactionReceive.amount, - ) - - // trigger to send transaction via dlt-connector - void sendTransactionsToDltConnector() - } catch (e) { - await queryRunner.rollbackTransaction() - throw new LogError('Transaction was not successful', e) - } finally { - await queryRunner.release() - } - void sendTransactionReceivedEmail({ - firstName: recipient.firstName, - lastName: recipient.lastName, - email: recipient.emailContact.email, - language: recipient.language, - senderFirstName: sender.firstName, - senderLastName: sender.lastName, - senderEmail: sender.emailContact.email, - transactionAmount: amount, - }) - if (transactionLink) { - void sendTransactionLinkRedeemedEmail({ - firstName: sender.firstName, - lastName: sender.lastName, - email: sender.emailContact.email, - language: sender.language, - senderFirstName: recipient.firstName, - senderLastName: recipient.lastName, - senderEmail: recipient.emailContact.email, - transactionAmount: amount, - transactionMemo: memo, - }) - } - logger.info(`finished executeTransaction successfully`) - } finally { - releaseLock() - } - return true -} -*/ - @Resolver() export class TransactionResolver { @Authorized([RIGHTS.TRANSACTION_LIST]) diff --git a/backend/src/graphql/resolver/util/processXComSendCoins.ts b/backend/src/graphql/resolver/util/processXComSendCoins.ts index 1cd443cd4..a7cf4c9f4 100644 --- a/backend/src/graphql/resolver/util/processXComSendCoins.ts +++ b/backend/src/graphql/resolver/util/processXComSendCoins.ts @@ -39,6 +39,23 @@ export async function processXComPendingSendCoins( sender, recipientIdentifier, ) + const openSenderPendingTx = await DbPendingTransaction.count({ + where: [ + { userGradidoID: sender.gradidoID, state: PendingTransactionState.NEW }, + { linkedUserGradidoID: sender.gradidoID, state: PendingTransactionState.NEW }, + ], + }) + const openReceiverPendingTx = await DbPendingTransaction.count({ + where: [ + { userGradidoID: recipientIdentifier, state: PendingTransactionState.NEW }, + { linkedUserGradidoID: recipientIdentifier, state: PendingTransactionState.NEW }, + ], + }) + if (openSenderPendingTx > 0 || openReceiverPendingTx > 0) { + throw new LogError( + `There exist still ongoing 'Pending-Transactions' for the involved users on sender-side!`, + ) + } // first calculate the sender balance and check if the transaction is allowed const senderBalance = await calculateSenderBalance(sender.id, amount.mul(-1), creationDate) if (!senderBalance) { @@ -77,10 +94,10 @@ export async function processXComPendingSendCoins( try { const pendingTx = DbPendingTransaction.create() pendingTx.amount = amount.mul(-1) - pendingTx.balance = senderBalance ? senderBalance.balance : new Decimal(0) + pendingTx.balance = senderBalance.balance pendingTx.balanceDate = creationDate - pendingTx.decay = senderBalance ? senderBalance.decay.decay : new Decimal(0) - pendingTx.decayStart = senderBalance ? senderBalance.decay.start : null + pendingTx.decay = senderBalance.decay.decay + pendingTx.decayStart = senderBalance.decay.start if (receiverCom.communityUuid) { pendingTx.linkedUserCommunityUuid = receiverCom.communityUuid } @@ -95,7 +112,7 @@ export async function processXComPendingSendCoins( pendingTx.state = PendingTransactionState.NEW pendingTx.typeId = TransactionTypeId.SEND if (senderCom.communityUuid) pendingTx.userCommunityUuid = senderCom.communityUuid - pendingTx.id = sender.id + pendingTx.userId = sender.id pendingTx.userGradidoID = sender.gradidoID pendingTx.userName = fullName(sender.firstName, sender.lastName) logger.debug(`X-Com: initialized sender pendingTX=`, pendingTx) @@ -126,6 +143,7 @@ export async function processXComPendingSendCoins( voteResult, ) } + return voteResult } } catch (err) { throw new LogError(`Error:`, err) @@ -156,12 +174,11 @@ export async function processXComCommittingSendCoins( ) // first find pending Tx with given parameters const pendingTx = await DbPendingTransaction.findOneBy({ - userCommunityUuid: senderCom.communityUuid ? senderCom.communityUuid : 'homeCom-UUID', + userCommunityUuid: senderCom.communityUuid ?? 'homeCom-UUID', userGradidoID: sender.gradidoID, userName: fullName(sender.firstName, sender.lastName), - linkedUserCommunityUuid: receiverCom.communityUuid - ? receiverCom.communityUuid - : CONFIG.FEDERATION_XCOM_RECEIVER_COMMUNITY_UUID, + linkedUserCommunityUuid: + receiverCom.communityUuid ?? CONFIG.FEDERATION_XCOM_RECEIVER_COMMUNITY_UUID, linkedUserGradidoID: recipUuid, typeId: TransactionTypeId.SEND, state: PendingTransactionState.NEW, @@ -187,7 +204,7 @@ export async function processXComCommittingSendCoins( args.recipientUserIdentifier = pendingTx.linkedUserGradidoID } args.creationDate = pendingTx.balanceDate.toISOString() - args.amount = pendingTx.amount + args.amount = pendingTx.amount.mul(-1) args.memo = pendingTx.memo args.senderCommunityUuid = pendingTx.userCommunityUuid args.senderUserUuid = pendingTx.userGradidoID diff --git a/backend/src/graphql/resolver/util/settlePendingSenderTransaction.ts b/backend/src/graphql/resolver/util/settlePendingSenderTransaction.ts index e22276823..eb100c621 100644 --- a/backend/src/graphql/resolver/util/settlePendingSenderTransaction.ts +++ b/backend/src/graphql/resolver/util/settlePendingSenderTransaction.ts @@ -15,6 +15,7 @@ import { calculateSenderBalance } from '@/util/calculateSenderBalance' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { getLastTransaction } from './getLastTransaction' +import Decimal from 'decimal.js-light' export async function settlePendingSenderTransaction( homeCom: DbCommunity, @@ -73,15 +74,13 @@ export async function settlePendingSenderTransaction( pendingTx.amount, pendingTx.balanceDate, ) - if (sendBalance?.balance !== pendingTx.balance) { - throw new LogError( - `X-Com: Calculation-Error on receiver balance: receiveBalance=${sendBalance?.balance}, pendingTx.balance=${pendingTx.balance}`, - ) + if (!sendBalance) { + throw new LogError(`Sender has not enough GDD or amount is < 0', sendBalance`) } - transactionSend.balance = pendingTx.balance + transactionSend.balance = sendBalance?.balance ?? new Decimal(0) transactionSend.balanceDate = pendingTx.balanceDate - transactionSend.decay = pendingTx.decay - transactionSend.decayStart = pendingTx.decayStart + transactionSend.decay = sendBalance.decay.decay // pendingTx.decay + transactionSend.decayStart = sendBalance.decay.start // pendingTx.decayStart transactionSend.previous = pendingTx.previous transactionSend.linkedTransactionId = pendingTx.linkedTransactionId await queryRunner.manager.insert(dbTransaction, transactionSend) diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index caa60c0d1..f2fe5a88f 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -78,12 +78,15 @@ export class SendCoinsResolver { try { const txDate = new Date(args.creationDate) const receiveBalance = await calculateRecipientBalance(receiverUser.id, args.amount, txDate) + if (!receiveBalance) { + throw new LogError('Receiver has not enough GDD or amount is < 0', receiveBalance) + } const pendingTx = DbPendingTransaction.create() pendingTx.amount = args.amount - pendingTx.balance = receiveBalance ? receiveBalance.balance : args.amount + pendingTx.balance = receiveBalance.balance pendingTx.balanceDate = txDate - pendingTx.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0) - pendingTx.decayStart = receiveBalance ? receiveBalance.decay.start : null + pendingTx.decay = receiveBalance.decay.decay + pendingTx.decayStart = receiveBalance.decay.start pendingTx.creationDate = new Date() pendingTx.linkedUserCommunityUuid = args.senderCommunityUuid pendingTx.linkedUserGradidoID = args.senderUserUuid diff --git a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts index 5c522061c..106b2beb1 100644 --- a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts @@ -77,18 +77,13 @@ export async function settlePendingReceiveTransaction( pendingTx.amount, pendingTx.balanceDate, ) - if ( - receiveBalance !== null && - receiveBalance.balance.toString() !== pendingTx.balance.toString() - ) { - throw new LogError( - `X-Com: Calculation-Error on receiver balance: receiveBalance=${receiveBalance.balance}, pendingTx.balance=${pendingTx.balance}`, - ) + if (!receiveBalance) { + throw new LogError(`Receiver has not enough GDD or amount is < 0', sendBalance`) } - transactionReceive.balance = receiveBalance ? receiveBalance.balance : pendingTx.amount + transactionReceive.balance = receiveBalance.balance transactionReceive.balanceDate = pendingTx.balanceDate - transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0) - transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null + transactionReceive.decay = receiveBalance.decay.decay + transactionReceive.decayStart = receiveBalance.decay.start transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null transactionReceive.linkedTransactionId = pendingTx.linkedTransactionId await queryRunner.manager.insert(dbTransaction, transactionReceive)