diff --git a/backend/src/federation/client/1_0/SendCoinsClient.ts b/backend/src/federation/client/1_0/SendCoinsClient.ts index e15e13100..f599dbafd 100644 --- a/backend/src/federation/client/1_0/SendCoinsClient.ts +++ b/backend/src/federation/client/1_0/SendCoinsClient.ts @@ -6,7 +6,6 @@ import { backendLogger as logger } from '@/server/logger' import { SendCoinsArgs } from './model/SendCoinsArgs' import { voteForSendCoins } from './query/voteForSendCoins' -import { SendCoinsResult } from './model/SendCoinsResult' // eslint-disable-next-line camelcase export class SendCoinsClient { @@ -28,25 +27,27 @@ export class SendCoinsClient { }) } - voteForSendCoins = async (args: SendCoinsArgs): Promise => { + voteForSendCoins = async (args: SendCoinsArgs): Promise => { logger.debug('X-Com: voteForSendCoins against endpoint', this.endpoint) try { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { data } = await this.client.rawRequest(voteForSendCoins, { args }) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!data?.voteForSendCoins?.SendCoinsResult.vote) { + if (!data?.voteForSendCoins?.voteForSendCoins) { logger.warn( 'X-Com: voteForSendCoins failed with: ', - data?.voteForSendCoins?.SendCoinsResult, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + data.voteForSendCoins.voteForSendCoins, ) - return null + return } logger.debug( 'X-Com: voteForSendCoins successful with result=', // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - data.voteForSendCoins.SendCoinsResult, + data.voteForSendCoins, ) - return data.voteForSendCoins.SendCoinsResult + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access + return data.voteForSendCoins.voteForSendCoins } catch (err) { throw new LogError(`X-Com: voteForSendCoins failed for endpoint=${this.endpoint}:`, err) } diff --git a/backend/src/graphql/resolver/util/processXComSendCoins.ts b/backend/src/graphql/resolver/util/processXComSendCoins.ts index 957522f65..1cd854c60 100644 --- a/backend/src/graphql/resolver/util/processXComSendCoins.ts +++ b/backend/src/graphql/resolver/util/processXComSendCoins.ts @@ -4,16 +4,17 @@ import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTrans import { User as dbUser } from '@entity/User' import { Decimal } from 'decimal.js-light' +import { CONFIG } from '@/config' import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs' // eslint-disable-next-line camelcase import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient' import { SendCoinsClientFactory } from '@/federation/client/SendCoinsClientFactory' -import { backendLogger as logger } from '@/server/logger' -import { CONFIG } from '@/config' -import { fullName } from '@/util/utilities' -import { calculateSenderBalance } from '@/util/calculateSenderBalance' +import { PendingTransactionState } from '@/graphql/enum/PendingTransactionState' +import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { LogError } from '@/server/LogError' - +import { backendLogger as logger } from '@/server/logger' +import { calculateSenderBalance } from '@/util/calculateSenderBalance' +import { fullName } from '@/util/utilities' export async function processXComSendCoins( receiverFCom: DbFederatedCommunity, @@ -27,6 +28,7 @@ export async function processXComSendCoins( recipient: dbUser, ): Promise { try { + // first calculate the sender balance and check if the transaction is allowed const senderBalance = await calculateSenderBalance(sender.id, amount.mul(-1), creationDate) if (!senderBalance) { throw new LogError('User has not enough GDD or amount is < 0', senderBalance) @@ -48,28 +50,35 @@ export async function processXComSendCoins( : 'homeCom-UUID' args.userSenderIdentifier = sender.gradidoID args.userSenderName = fullName(sender.firstName, sender.lastName) - const result = await client.voteForSendCoins(args) - if(result) { - const pendingTx = DbPendingTransaction.create() - pendingTx.amount = amount.mul(-1) - pendingTx.balance = senderBalance ? senderBalance.balance : new Decimal(0) - pendingTx.balanceDate = creationDate - pendingTx.decay = senderBalance ? senderBalance.decay.decay : new Decimal(0) - pendingTx.decayStart = senderBalance ? senderBalance.decay.start : null - pendingTx.linkedUserCommunityUuid = receiverCom.communityUuid - ? receiverCom.communityUuid - : CONFIG.FEDERATION_XCOM_RECEIVER_COMMUNITY_UUID - pendingTx.linkedUserGradidoID = recipient.gradidoID - pendingTx.linkedUserName = userSenderName - pendingTx.memo = memo - pendingTx.previous = receiveBalance ? receiveBalance.lastTransactionId : null - pendingTx.state = PendingTransactionState.NEW - pendingTx.typeId = TransactionTypeId.RECEIVE - pendingTx.userCommunityUuid = communityReceiverIdentifier - pendingTx.userGradidoID = userReceiverIdentifier - pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName) + const recipientName = await client.voteForSendCoins(args) + if (recipientName) { + // writing the pending transaction on receiver-side was successfull, so now write the sender side + try { + const pendingTx = DbPendingTransaction.create() + pendingTx.amount = amount.mul(-1) + pendingTx.balance = senderBalance ? senderBalance.balance : new Decimal(0) + pendingTx.balanceDate = creationDate + pendingTx.decay = senderBalance ? senderBalance.decay.decay : new Decimal(0) + pendingTx.decayStart = senderBalance ? senderBalance.decay.start : null + pendingTx.linkedUserCommunityUuid = receiverCom.communityUuid + ? receiverCom.communityUuid + : CONFIG.FEDERATION_XCOM_RECEIVER_COMMUNITY_UUID + pendingTx.linkedUserGradidoID = recipient.gradidoID + pendingTx.linkedUserName = recipientName + pendingTx.memo = memo + pendingTx.previous = senderBalance ? senderBalance.lastTransactionId : null + pendingTx.state = PendingTransactionState.NEW + pendingTx.typeId = TransactionTypeId.SEND + if (senderCom.communityUuid) pendingTx.userCommunityUuid = senderCom.communityUuid + pendingTx.userGradidoID = sender.gradidoID + pendingTx.userName = fullName(sender.firstName, sender.lastName) - await DbPendingTransaction.insert(pendingTx) + await DbPendingTransaction.insert(pendingTx) + } catch (err) { + logger.error(`Error in writing sender pending transaction: `, err) + // revert the existing pending transaction on receiver side + // TODO in the issue #3186 + } logger.debug(`voteForSendCoins()-1_0... successfull`) } } diff --git a/federation/src/graphql/api/1_0/model/SendCoinsResult.ts b/federation/src/graphql/api/1_0/model/SendCoinsResult.ts deleted file mode 100644 index 1897410cc..000000000 --- a/federation/src/graphql/api/1_0/model/SendCoinsResult.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ArgsType, Field } from 'type-graphql' - -@ArgsType() -export class SendCoinsResult { - constructor() { - this.vote = false - } - - @Field(() => Boolean) - vote: boolean - - @Field(() => String) - receiverFirstName: string - - @Field(() => String) - receiverLastName: string -} diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index 73c6e077c..ba23ae530 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -11,7 +11,6 @@ import { TransactionTypeId } from '../enum/TransactionTypeId' import { calculateRecepientBalance } from '@/graphql/util/calculateRecepientBalance' import Decimal from 'decimal.js-light' import { fullName } from '@/graphql/util/fullName' -import { SendCoinsResult } from '../model/SendCoinsResult' @Resolver() // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -29,9 +28,9 @@ export class SendCoinsResolver { userSenderIdentifier, userSenderName, }: SendCoinsArgs, - ): Promise { - const result = new SendCoinsResult() + ): Promise { logger.debug(`voteForSendCoins() via apiVersion=1_0 ...`) + let result: string | null = null try { // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ @@ -70,9 +69,7 @@ export class SendCoinsResolver { pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName) await DbPendingTransaction.insert(pendingTx) - result.vote = true - result.receiverFirstName = receiverUser.firstName - result.receiverLastName = receiverUser.lastName + result = pendingTx.userName logger.debug(`voteForSendCoins()-1_0... successfull`) } catch (err) { throw new LogError(`Error in voteForSendCoins: `, err)