From fade56a55760e60a016db3c09d003ca6018caafe Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Thu, 28 Sep 2023 00:40:48 +0200 Subject: [PATCH] additional tests for x-com-sendcoins --- .../federation/client/1_0/SendCoinsClient.ts | 78 +-- .../client/1_0/model/SendCoinsResult.ts | 12 +- .../client/1_0/query/revertSendCoins.ts | 7 +- .../1_0/query/revertSettledSendCoins.ts | 8 +- .../client/1_0/query/settleSendCoins.ts | 7 +- .../client/1_0/query/voteForSendCoins.ts | 36 +- federation/jest.config.js | 2 +- .../graphql/api/1_0/model/SendCoinsArgs.ts | 4 +- .../graphql/api/1_0/model/SendCoinsResult.ts | 17 + .../1_0/resolver/SendCoinsResolver.test.ts | 456 +++++++++--------- .../api/1_0/resolver/SendCoinsResolver.ts | 243 +++++----- .../util/revertSettledReceiveTransaction.ts | 21 +- .../util/settlePendingReceiveTransaction.ts | 8 - 13 files changed, 500 insertions(+), 399 deletions(-) create mode 100644 federation/src/graphql/api/1_0/model/SendCoinsResult.ts diff --git a/backend/src/federation/client/1_0/SendCoinsClient.ts b/backend/src/federation/client/1_0/SendCoinsClient.ts index 7f1fad186..3b3bf4f2c 100644 --- a/backend/src/federation/client/1_0/SendCoinsClient.ts +++ b/backend/src/federation/client/1_0/SendCoinsClient.ts @@ -5,6 +5,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { SendCoinsArgs } from './model/SendCoinsArgs' +import { SendCoinsResult } from './model/SendCoinsResult' import { revertSendCoins } from './query/revertSendCoins' import { revertSettledSendCoins } from './query/revertSettledSendCoins' import { settleSendCoins } from './query/settleSendCoins' @@ -22,7 +23,7 @@ export class SendCoinsClient { dbCom.apiVersion }/` this.client = new GraphQLClient(this.endpoint, { - method: 'GET', + method: 'POST', jsonSerializer: { parse: JSON.parse, stringify: JSON.stringify, @@ -30,27 +31,26 @@ export class SendCoinsClient { }) } - voteForSendCoins = async (args: SendCoinsArgs): Promise => { + voteForSendCoins = async (args: SendCoinsArgs): Promise => { logger.debug('X-Com: voteForSendCoins against endpoint=', this.endpoint) try { + logger.debug(`X-Com: SendCoinsClient: voteForSendCoins with args=`, args) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { data } = await this.client.rawRequest(voteForSendCoins, { args }) + logger.debug(`X-Com: SendCoinsClient: after rawRequest...data:`, data) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!data?.voteForSendCoins?.voteForSendCoins) { - logger.warn( - 'X-Com: voteForSendCoins failed with: ', - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - data.voteForSendCoins.voteForSendCoins, - ) - return + if (!data?.voteForSendCoins?.vote) { + logger.warn('X-Com: voteForSendCoins failed with: ', data) + return new SendCoinsResult() } - logger.debug( - 'X-Com: voteForSendCoins successful with result=', - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - data.voteForSendCoins, - ) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access - return data.voteForSendCoins.voteForSendCoins + const result = new SendCoinsResult() + result.vote = true + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + result.recipGradidoID = data.voteForSendCoins.recipGradidoID + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + result.recipName = data.voteForSendCoins.recipName + logger.debug('X-Com: voteForSendCoins successful with result=', result) + return result } catch (err) { throw new LogError(`X-Com: voteForSendCoins failed for endpoint=${this.endpoint}:`, err) } @@ -59,17 +59,24 @@ export class SendCoinsClient { revertSendCoins = async (args: SendCoinsArgs): Promise => { logger.debug('X-Com: revertSendCoins against endpoint=', this.endpoint) try { + logger.debug(`X-Com: SendCoinsClient: revertSendCoins with args=`, args) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 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 } - logger.debug(`X-Com: revertSendCoins successful from endpoint=${this.endpoint}`) + logger.debug( + `X-Com: SendCoinsClient: revertSendCoins successful from endpoint=${this.endpoint}`, + ) return true } catch (err) { - logger.error(`X-Com: revertSendCoins failed for endpoint=${this.endpoint}`, err) + logger.error( + `X-Com: SendCoinsClient: revertSendCoins failed for endpoint=${this.endpoint}`, + err, + ) return false } } @@ -77,37 +84,54 @@ export class SendCoinsClient { settleSendCoins = async (args: SendCoinsArgs): Promise => { logger.debug(`X-Com: settleSendCoins against endpoint='${this.endpoint}'...`) try { + logger.debug(`X-Com: SendCoinsClient: settleSendCoins with args=`, args) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 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) { - logger.warn('X-Com: settleSendCoins without response data from endpoint', this.endpoint) + if (!data?.settleSendCoins) { + logger.warn( + 'X-Com: SendCoinsClient: settleSendCoins without response data from endpoint', + this.endpoint, + ) return false } - logger.debug(`X-Com: settleSendCoins successful from endpoint=${this.endpoint}`) + logger.debug( + `X-Com: SendCoinsClient: settleSendCoins successful from endpoint=${this.endpoint}`, + ) return true } catch (err) { - throw new LogError(`X-Com: settleSendCoins failed for endpoint=${this.endpoint}`, err) + throw new LogError( + `X-Com: SendCoinsClient: settleSendCoins failed for endpoint=${this.endpoint}`, + err, + ) } } revertSettledSendCoins = async (args: SendCoinsArgs): Promise => { logger.debug(`X-Com: revertSettledSendCoins against endpoint='${this.endpoint}'...`) try { + logger.debug(`X-Com: SendCoinsClient: revertSettledSendCoins with args=`, args) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 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: revertSettledSendCoins without response data from endpoint', + 'X-Com: SendCoinsClient: revertSettledSendCoins without response data from endpoint', this.endpoint, ) return false } - logger.debug(`X-Com: revertSettledSendCoins successful from endpoint=${this.endpoint}`) + logger.debug( + `X-Com: SendCoinsClient: revertSettledSendCoins successful from endpoint=${this.endpoint}`, + ) return true } catch (err) { - throw new LogError(`X-Com: revertSettledSendCoins failed for endpoint=${this.endpoint}`, err) + throw new LogError( + `X-Com: SendCoinsClient: revertSettledSendCoins failed for endpoint=${this.endpoint}`, + err, + ) } } } diff --git a/backend/src/federation/client/1_0/model/SendCoinsResult.ts b/backend/src/federation/client/1_0/model/SendCoinsResult.ts index 1897410cc..930d22ff5 100644 --- a/backend/src/federation/client/1_0/model/SendCoinsResult.ts +++ b/backend/src/federation/client/1_0/model/SendCoinsResult.ts @@ -1,6 +1,6 @@ -import { ArgsType, Field } from 'type-graphql' +import { Field, ObjectType } from 'type-graphql' -@ArgsType() +@ObjectType() export class SendCoinsResult { constructor() { this.vote = false @@ -9,9 +9,9 @@ export class SendCoinsResult { @Field(() => Boolean) vote: boolean - @Field(() => String) - receiverFirstName: string + @Field(() => String, { nullable: true }) + recipGradidoID: string | null - @Field(() => String) - receiverLastName: string + @Field(() => String, { nullable: true }) + recipName: string | null } diff --git a/backend/src/federation/client/1_0/query/revertSendCoins.ts b/backend/src/federation/client/1_0/query/revertSendCoins.ts index 9cc23fe64..ea7d28f77 100644 --- a/backend/src/federation/client/1_0/query/revertSendCoins.ts +++ b/backend/src/federation/client/1_0/query/revertSendCoins.ts @@ -1,6 +1,11 @@ import { gql } from 'graphql-request' export const revertSendCoins = gql` + mutation ($args: SendCoinsArgs!) { + revertSendCoins(data: $args) + } +` +/* mutation ( $recipientCommunityUuid: String! $recipientUserIdentifier: String! @@ -22,4 +27,4 @@ export const revertSendCoins = gql` senderUserName: $senderUserName ) } -` +*/ diff --git a/backend/src/federation/client/1_0/query/revertSettledSendCoins.ts b/backend/src/federation/client/1_0/query/revertSettledSendCoins.ts index 74cdbd867..3965df396 100644 --- a/backend/src/federation/client/1_0/query/revertSettledSendCoins.ts +++ b/backend/src/federation/client/1_0/query/revertSettledSendCoins.ts @@ -1,6 +1,12 @@ import { gql } from 'graphql-request' export const revertSettledSendCoins = gql` + mutation ($args: SendCoinsArgs!) { + revertSettledSendCoins(data: $args) + } +` +/* + mutation ( $recipientCommunityUuid: String! $recipientUserIdentifier: String! @@ -22,4 +28,4 @@ export const revertSettledSendCoins = gql` senderUserName: $senderUserName ) } -` +*/ diff --git a/backend/src/federation/client/1_0/query/settleSendCoins.ts b/backend/src/federation/client/1_0/query/settleSendCoins.ts index 1696a0900..206a6544c 100644 --- a/backend/src/federation/client/1_0/query/settleSendCoins.ts +++ b/backend/src/federation/client/1_0/query/settleSendCoins.ts @@ -1,6 +1,11 @@ import { gql } from 'graphql-request' export const settleSendCoins = gql` + mutation ($args: SendCoinsArgs!) { + settleSendCoins(data: $args) + } +` +/* mutation ( $recipientCommunityUuid: String! $recipientUserIdentifier: String! @@ -22,4 +27,4 @@ export const settleSendCoins = gql` senderUserName: $senderUserName ) } -` +*/ \ No newline at end of file diff --git a/backend/src/federation/client/1_0/query/voteForSendCoins.ts b/backend/src/federation/client/1_0/query/voteForSendCoins.ts index 0f16ff32b..a5456bec7 100644 --- a/backend/src/federation/client/1_0/query/voteForSendCoins.ts +++ b/backend/src/federation/client/1_0/query/voteForSendCoins.ts @@ -1,6 +1,16 @@ import { gql } from 'graphql-request' export const voteForSendCoins = gql` + mutation ($args: SendCoinsArgs!) { + voteForSendCoins(data: $args) { + vote + recipGradidoID + recipName + } + } +` + +/* mutation ( $recipientCommunityUuid: String! $recipientUserIdentifier: String! @@ -12,14 +22,20 @@ export const voteForSendCoins = gql` $senderUserName: String! ) { voteForSendCoins( - recipientCommunityUuid: $recipientCommunityUuid - recipientUserIdentifier: $recipientUserIdentifier - creationDate: $creationDate - amount: $amount - memo: $memo - senderCommunityUuid: $senderCommunityUuid - senderUserUuid: $senderUserUuid - senderUserName: $senderUserName - ) + data: { + recipientCommunityUuid: $recipientCommunityUuid + recipientUserIdentifier: $recipientUserIdentifier + creationDate: $creationDate + amount: $amount + memo: $memo + senderCommunityUuid: $senderCommunityUuid + senderUserUuid: $senderUserUuid + senderUserName: $senderUserName + } + ) { + vote + recipGradidoID + recipName + } } -` +*/ diff --git a/federation/jest.config.js b/federation/jest.config.js index cffb79835..f859bbe2f 100644 --- a/federation/jest.config.js +++ b/federation/jest.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 74, + lines: 75, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/federation/src/graphql/api/1_0/model/SendCoinsArgs.ts b/federation/src/graphql/api/1_0/model/SendCoinsArgs.ts index fb97da925..e658209ca 100644 --- a/federation/src/graphql/api/1_0/model/SendCoinsArgs.ts +++ b/federation/src/graphql/api/1_0/model/SendCoinsArgs.ts @@ -1,7 +1,7 @@ import { Decimal } from 'decimal.js-light' -import { ArgsType, Field } from 'type-graphql' +import { Field, InputType } from 'type-graphql' -@ArgsType() +@InputType() export class SendCoinsArgs { @Field(() => String) recipientCommunityUuid: string diff --git a/federation/src/graphql/api/1_0/model/SendCoinsResult.ts b/federation/src/graphql/api/1_0/model/SendCoinsResult.ts new file mode 100644 index 000000000..930d22ff5 --- /dev/null +++ b/federation/src/graphql/api/1_0/model/SendCoinsResult.ts @@ -0,0 +1,17 @@ +import { Field, ObjectType } from 'type-graphql' + +@ObjectType() +export class SendCoinsResult { + constructor() { + this.vote = false + } + + @Field(() => Boolean) + vote: boolean + + @Field(() => String, { nullable: true }) + recipGradidoID: string | null + + @Field(() => String, { nullable: true }) + recipName: string | null +} diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.test.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.test.ts index 5120391d6..897e06179 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.test.ts @@ -15,6 +15,7 @@ import Decimal from 'decimal.js-light' import { PendingTransactionState } from '../enum/PendingTransactionState' import { TransactionTypeId } from '../enum/TransactionTypeId' import { Transaction as DbTransaction } from '@entity/Transaction' +import { SendCoinsArgs } from '../model/SendCoinsArgs' let mutate: ApolloServerTestClient['mutate'], con: Connection // let query: ApolloServerTestClient['query'] @@ -49,49 +50,24 @@ afterAll(async () => { describe('SendCoinsResolver', () => { const voteForSendCoinsMutation = ` - mutation ( - $recipientCommunityUuid: String! - $recipientUserIdentifier: String! - $creationDate: String! - $amount: Decimal! - $memo: String! - $senderCommunityUuid: String! - $senderUserUuid: String! - $senderUserName: String! - ) { - voteForSendCoins( - recipientCommunityUuid: $recipientCommunityUuid - recipientUserIdentifier: $recipientUserIdentifier - creationDate: $creationDate - amount: $amount - memo: $memo - senderCommunityUuid: $senderCommunityUuid - senderUserUuid: $senderUserUuid - senderUserName: $senderUserName - ) + mutation ($args: SendCoinsArgs!) { + voteForSendCoins(data: $args) { + vote + recipGradidoID + recipName + } }` - const settleSendCoinsMutation = ` - mutation ( - $recipientCommunityUuid: String! - $recipientUserIdentifier: String! - $creationDate: String! - $amount: Decimal! - $memo: String! - $senderCommunityUuid: String! - $senderUserUuid: String! - $senderUserName: String! - ) { - settleSendCoins( - recipientCommunityUuid: $recipientCommunityUuid - recipientUserIdentifier: $recipientUserIdentifier - creationDate: $creationDate - amount: $amount - memo: $memo - senderCommunityUuid: $senderCommunityUuid - senderUserUuid: $senderUserUuid - senderUserName: $senderUserName - ) + mutation ($args: SendCoinsArgs!) { + settleSendCoins(data: $args) + }` + const revertSendCoinsMutation = ` + mutation ($args: SendCoinsArgs!) { + revertSendCoins(data: $args) + }` + const revertSettledSendCoinsMutation = ` + mutation ($args: SendCoinsArgs!) { + revertSettledSendCoins(data: $args) }` beforeEach(async () => { @@ -149,19 +125,21 @@ describe('SendCoinsResolver', () => { describe('unknown recipient community', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + args.recipientCommunityUuid = 'invalid foreignCom' + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = new Date().toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: voteForSendCoinsMutation, - variables: { - recipientCommunityUuid: 'invalid foreignCom', - recipientUserIdentifier: recipUser.gradidoID, - creationDate: new Date().toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -174,19 +152,23 @@ describe('SendCoinsResolver', () => { describe('unknown recipient user', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = 'invalid recipient' + args.creationDate = new Date().toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: voteForSendCoinsMutation, - variables: { - recipientCommunityUuid: foreignCom.communityUuid, - recipientUserIdentifier: 'invalid recipient', - creationDate: new Date().toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -203,24 +185,32 @@ describe('SendCoinsResolver', () => { describe('valid X-Com-TX voted', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = new Date().toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: voteForSendCoinsMutation, - variables: { - recipientCommunityUuid: foreignCom.communityUuid, - recipientUserIdentifier: recipUser.gradidoID, - creationDate: new Date().toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ data: { - voteForSendCoins: 'recipUser-FirstName recipUser-LastName', + voteForSendCoins: { + recipGradidoID: '56a55482-909e-46a4-bfa2-cd025e894ebd', + recipName: 'recipUser-FirstName recipUser-LastName', + vote: true, + }, }, }), ) @@ -229,63 +219,46 @@ describe('SendCoinsResolver', () => { }) describe('revertSendCoins', () => { - const revertSendCoinsMutation = ` - mutation ( - $recipientCommunityUuid: String! - $recipientUserIdentifier: String! - $creationDate: String! - $amount: Decimal! - $memo: String! - $senderCommunityUuid: String! - $senderUserUuid: String! - $senderUserName: String! - ) { - revertSendCoins( - recipientCommunityUuid: $recipientCommunityUuid - recipientUserIdentifier: $recipientUserIdentifier - creationDate: $creationDate - amount: $amount - memo: $memo - senderCommunityUuid: $senderCommunityUuid - senderUserUuid: $senderUserUuid - senderUserName: $senderUserName - ) - }` - const creationDate = new Date() beforeEach(async () => { + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) await mutate({ mutation: voteForSendCoinsMutation, - variables: { - recipientCommunityUuid: foreignCom.communityUuid, - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }) }) describe('unknown recipient community', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + args.recipientCommunityUuid = 'invalid foreignCom' + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: revertSendCoinsMutation, - variables: { - recipientCommunityUuid: 'invalid foreignCom', - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -298,19 +271,23 @@ describe('SendCoinsResolver', () => { describe('unknown recipient user', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = 'invalid recipient' + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: revertSendCoinsMutation, - variables: { - recipientCommunityUuid: foreignCom.communityUuid, - recipientUserIdentifier: 'invalid recipient', - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -327,19 +304,23 @@ describe('SendCoinsResolver', () => { describe('valid X-Com-TX reverted', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: revertSendCoinsMutation, - variables: { - recipientCommunityUuid: foreignCom.communityUuid, - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: homeCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -357,6 +338,24 @@ describe('SendCoinsResolver', () => { const creationDate = new Date() beforeEach(async () => { + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) + await mutate({ + mutation: voteForSendCoinsMutation, + variables: { args }, + }) + /* pendingTx = DbPendingTransaction.create() pendingTx.amount = new Decimal(100) pendingTx.balanceDate = creationDate @@ -375,24 +374,27 @@ describe('SendCoinsResolver', () => { } pendingTx.userGradidoID = recipUser.gradidoID await DbPendingTransaction.insert(pendingTx) + */ }) describe('unknown recipient community', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + args.recipientCommunityUuid = 'invalid foreignCom' + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: settleSendCoinsMutation, - variables: { - recipientCommunityUuid: 'invalid foreignCom', - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: foreignCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -405,19 +407,23 @@ describe('SendCoinsResolver', () => { describe('unknown recipient user', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = 'invalid recipient' + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: settleSendCoinsMutation, - variables: { - recipientCommunityUuid: homeCom.communityUuid, - recipientUserIdentifier: 'invalid recipient', - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: foreignCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -434,19 +440,23 @@ describe('SendCoinsResolver', () => { describe('valid X-Com-TX settled', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: settleSendCoinsMutation, - variables: { - recipientCommunityUuid: homeCom.communityUuid, - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: foreignCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -460,34 +470,33 @@ describe('SendCoinsResolver', () => { }) describe('revertSettledSendCoins', () => { - const revertSettledSendCoinsMutation = ` - mutation ( - $recipientCommunityUuid: String! - $recipientUserIdentifier: String! - $creationDate: String! - $amount: Decimal! - $memo: String! - $senderCommunityUuid: String! - $senderUserUuid: String! - $senderUserName: String! - ) { - revertSettledSendCoins( - recipientCommunityUuid: $recipientCommunityUuid - recipientUserIdentifier: $recipientUserIdentifier - creationDate: $creationDate - amount: $amount - memo: $memo - senderCommunityUuid: $senderCommunityUuid - senderUserUuid: $senderUserUuid - senderUserName: $senderUserName - ) - }` - let pendingTx: DbPendingTransaction let settledTx: DbTransaction const creationDate = new Date() beforeEach(async () => { + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) + await mutate({ + mutation: voteForSendCoinsMutation, + variables: { args }, + }) + await mutate({ + mutation: settleSendCoinsMutation, + variables: { args }, + }) + /* pendingTx = DbPendingTransaction.create() pendingTx.amount = new Decimal(100) pendingTx.balanceDate = creationDate @@ -524,24 +533,27 @@ describe('SendCoinsResolver', () => { } settledTx.userGradidoID = recipUser.gradidoID await DbTransaction.insert(settledTx) + */ }) describe('unknown recipient community', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + args.recipientCommunityUuid = 'invalid foreignCom' + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: revertSettledSendCoinsMutation, - variables: { - recipientCommunityUuid: 'invalid foreignCom', - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: foreignCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -554,19 +566,23 @@ describe('SendCoinsResolver', () => { describe('unknown recipient user', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = 'invalid recipient' + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: revertSettledSendCoinsMutation, - variables: { - recipientCommunityUuid: homeCom.communityUuid, - recipientUserIdentifier: 'invalid recipient', - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: foreignCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ @@ -583,19 +599,23 @@ describe('SendCoinsResolver', () => { describe('valid X-Com-TX settled', () => { it('throws an error', async () => { jest.clearAllMocks() + const args = new SendCoinsArgs() + if (foreignCom.communityUuid) { + args.recipientCommunityUuid = foreignCom.communityUuid + } + args.recipientUserIdentifier = recipUser.gradidoID + args.creationDate = creationDate.toISOString() + args.amount = new Decimal(100) + args.memo = 'X-Com-TX memo' + if (homeCom.communityUuid) { + args.senderCommunityUuid = homeCom.communityUuid + } + args.senderUserUuid = sendUser.gradidoID + args.senderUserName = fullName(sendUser.firstName, sendUser.lastName) expect( await mutate({ mutation: revertSettledSendCoinsMutation, - variables: { - recipientCommunityUuid: homeCom.communityUuid, - recipientUserIdentifier: recipUser.gradidoID, - creationDate: creationDate.toISOString(), - amount: 100, - memo: 'X-Com-TX memo', - senderCommunityUuid: foreignCom.communityUuid, - senderUserUuid: sendUser.gradidoID, - senderUserName: fullName(sendUser.firstName, sendUser.lastName), - }, + variables: { args }, }), ).toEqual( expect.objectContaining({ diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index 4196e015c..d942c48f3 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -1,5 +1,5 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Args, Mutation, Resolver } from 'type-graphql' +import { Arg, Args, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction' @@ -8,56 +8,48 @@ import { LogError } from '@/server/LogError' import { PendingTransactionState } from '../enum/PendingTransactionState' import { TransactionTypeId } from '../enum/TransactionTypeId' import { calculateRecipientBalance } from '../util/calculateRecipientBalance' -import Decimal from 'decimal.js-light' import { fullName } from '@/graphql/util/fullName' import { settlePendingReceiveTransaction } from '../util/settlePendingReceiveTransaction' // import { checkTradingLevel } from '@/graphql/util/checkTradingLevel' import { revertSettledReceiveTransaction } from '../util/revertSettledReceiveTransaction' import { findUserByIdentifier } from '@/graphql/util/findUserByIdentifier' +import { SendCoinsResult } from '../model/SendCoinsResult' +import Decimal from 'decimal.js-light' @Resolver() // eslint-disable-next-line @typescript-eslint/no-unused-vars export class SendCoinsResolver { - @Mutation(() => String) + @Mutation(() => SendCoinsResult) async voteForSendCoins( - @Args() - { - recipientCommunityUuid, - recipientUserIdentifier, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, - }: SendCoinsArgs, - ): Promise { + @Arg('data') + args: SendCoinsArgs, + ): Promise { logger.debug( `voteForSendCoins() via apiVersion=1_0 ...`, - recipientCommunityUuid, - recipientUserIdentifier, - creationDate, - amount.toString(), - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, + args.recipientCommunityUuid, + args.recipientUserIdentifier, + args.creationDate, + args.amount.toString(), + args.memo, + args.senderCommunityUuid, + args.senderUserUuid, + args.senderUserName, ) - let result: string + const result = new SendCoinsResult() // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ - communityUuid: recipientCommunityUuid, + communityUuid: args.recipientCommunityUuid, }) if (!homeCom) { throw new LogError( `voteForSendCoins with wrong recipientCommunityUuid`, - recipientCommunityUuid, + args.recipientCommunityUuid, ) } let receiverUser try { // second check if receiver user exists in this community - receiverUser = await findUserByIdentifier(recipientUserIdentifier) + receiverUser = await findUserByIdentifier(args.recipientUserIdentifier) } catch (err) { logger.error('Error in findUserByIdentifier:', err) throw new LogError( @@ -65,30 +57,50 @@ export class SendCoinsResolver { homeCom.name, ) } + const openSenderPendingTx = await DbPendingTransaction.count({ + where: [ + { userGradidoID: args.senderUserUuid, state: PendingTransactionState.NEW }, + { linkedUserGradidoID: args.senderUserUuid, state: PendingTransactionState.NEW }, + ], + }) + const openReceiverPendingTx = await DbPendingTransaction.count({ + where: [ + { userGradidoID: receiverUser.gradidoID, state: PendingTransactionState.NEW }, + { linkedUserGradidoID: receiverUser.gradidoID, state: PendingTransactionState.NEW }, + ], + }) + if (openSenderPendingTx > 0 || openReceiverPendingTx > 0) { + throw new LogError( + `There exist still ongoing 'Pending-Transactions' for the involved users on receiver-side!`, + ) + } + try { - const txDate = new Date(creationDate) - const receiveBalance = await calculateRecipientBalance(receiverUser.id, amount, txDate) + const txDate = new Date(args.creationDate) + const receiveBalance = await calculateRecipientBalance(receiverUser.id, args.amount, txDate) const pendingTx = DbPendingTransaction.create() - pendingTx.amount = amount - pendingTx.balance = receiveBalance ? receiveBalance.balance : amount + pendingTx.amount = args.amount + pendingTx.balance = receiveBalance ? receiveBalance.balance : args.amount pendingTx.balanceDate = txDate pendingTx.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0) pendingTx.decayStart = receiveBalance ? receiveBalance.decay.start : null pendingTx.creationDate = new Date() - pendingTx.linkedUserCommunityUuid = senderCommunityUuid - pendingTx.linkedUserGradidoID = senderUserUuid - pendingTx.linkedUserName = senderUserName - pendingTx.memo = memo + pendingTx.linkedUserCommunityUuid = args.senderCommunityUuid + pendingTx.linkedUserGradidoID = args.senderUserUuid + pendingTx.linkedUserName = args.senderUserName + pendingTx.memo = args.memo pendingTx.previous = receiveBalance ? receiveBalance.lastTransactionId : null pendingTx.state = PendingTransactionState.NEW pendingTx.typeId = TransactionTypeId.RECEIVE pendingTx.userId = receiverUser.id - pendingTx.userCommunityUuid = recipientCommunityUuid + pendingTx.userCommunityUuid = args.recipientCommunityUuid pendingTx.userGradidoID = receiverUser.gradidoID pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName) await DbPendingTransaction.insert(pendingTx) - result = pendingTx.userName + result.vote = true + result.recipName = pendingTx.userName + result.recipGradidoID = pendingTx.userGradidoID logger.debug(`voteForSendCoins()-1_0... successfull`) } catch (err) { throw new LogError(`Error in voteForSendCoins: `, err) @@ -98,33 +110,24 @@ export class SendCoinsResolver { @Mutation(() => Boolean) async revertSendCoins( - @Args() - { - recipientCommunityUuid, - recipientUserIdentifier, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, - }: SendCoinsArgs, + @Arg('data') + args: SendCoinsArgs, ): Promise { logger.debug(`revertSendCoins() via apiVersion=1_0 ...`) // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ - communityUuid: recipientCommunityUuid, + communityUuid: args.recipientCommunityUuid, }) if (!homeCom) { throw new LogError( `revertSendCoins with wrong recipientCommunityUuid`, - recipientCommunityUuid, + args.recipientCommunityUuid, ) } let receiverUser try { // second check if receiver user exists in this community - receiverUser = await findUserByIdentifier(recipientUserIdentifier) + receiverUser = await findUserByIdentifier(args.recipientUserIdentifier) } catch (err) { logger.error('Error in findUserByIdentifier:', err) throw new LogError( @@ -134,16 +137,16 @@ export class SendCoinsResolver { } try { const pendingTx = await DbPendingTransaction.findOneBy({ - userCommunityUuid: recipientCommunityUuid, + userCommunityUuid: args.recipientCommunityUuid, userGradidoID: receiverUser.gradidoID, state: PendingTransactionState.NEW, typeId: TransactionTypeId.RECEIVE, - balanceDate: new Date(creationDate), - linkedUserCommunityUuid: senderCommunityUuid, - linkedUserGradidoID: senderUserUuid, + balanceDate: new Date(args.creationDate), + linkedUserCommunityUuid: args.senderCommunityUuid, + linkedUserGradidoID: args.senderUserUuid, }) logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx) - if (pendingTx && pendingTx.amount.toString() === amount.toString()) { + if (pendingTx && pendingTx.amount.toString() === args.amount.toString()) { logger.debug('XCom: revertSendCoins matching pendingTX for remove...') try { await pendingTx.remove() @@ -154,21 +157,21 @@ export class SendCoinsResolver { } else { logger.debug( 'XCom: revertSendCoins NOT matching pendingTX for remove:', - pendingTx?.amount, - amount, + pendingTx?.amount.toString(), + args.amount.toString(), ) throw new LogError( `Can't find in revertSendCoins the pending receiver TX for args=`, - recipientCommunityUuid, - recipientUserIdentifier, + args.recipientCommunityUuid, + args.recipientUserIdentifier, PendingTransactionState.NEW, TransactionTypeId.RECEIVE, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, + args.creationDate, + args.amount, + args.memo, + args.senderCommunityUuid, + args.senderUserUuid, + args.senderUserName, ) } logger.debug(`revertSendCoins()-1_0... successfull`) @@ -180,35 +183,32 @@ export class SendCoinsResolver { @Mutation(() => Boolean) async settleSendCoins( - @Args() - { - recipientCommunityUuid, - recipientUserIdentifier, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, - }: SendCoinsArgs, + @Arg('data') + args: SendCoinsArgs, ): Promise { logger.debug( - `settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${recipientCommunityUuid}, userGradidoID=${recipientUserIdentifier}, balanceDate=${creationDate},amount=${amount.valueOf()}, memo=${memo}, linkedUserCommunityUuid = ${senderCommunityUuid}, userSenderIdentifier=${senderUserUuid}, userSenderName=${senderUserName}`, + `settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${ + args.recipientCommunityUuid + }, userGradidoID=${args.recipientUserIdentifier}, balanceDate=${ + args.creationDate + },amount=${args.amount.valueOf()}, memo=${args.memo}, linkedUserCommunityUuid = ${ + args.senderCommunityUuid + }, userSenderIdentifier=${args.senderUserUuid}, userSenderName=${args.senderUserName}`, ) // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ - communityUuid: recipientCommunityUuid, + communityUuid: args.recipientCommunityUuid, }) if (!homeCom) { throw new LogError( `settleSendCoins with wrong recipientCommunityUuid`, - recipientCommunityUuid, + args.recipientCommunityUuid, ) } let receiverUser try { // second check if receiver user exists in this community - receiverUser = await findUserByIdentifier(recipientUserIdentifier) + receiverUser = await findUserByIdentifier(args.recipientUserIdentifier) } catch (err) { logger.error('Error in findUserByIdentifier:', err) throw new LogError( @@ -217,16 +217,20 @@ export class SendCoinsResolver { ) } const pendingTx = await DbPendingTransaction.findOneBy({ - userCommunityUuid: recipientCommunityUuid, + userCommunityUuid: args.recipientCommunityUuid, userGradidoID: receiverUser.gradidoID, state: PendingTransactionState.NEW, typeId: TransactionTypeId.RECEIVE, - balanceDate: new Date(creationDate), - linkedUserCommunityUuid: senderCommunityUuid, - linkedUserGradidoID: senderUserUuid, + balanceDate: new Date(args.creationDate), + linkedUserCommunityUuid: args.senderCommunityUuid, + linkedUserGradidoID: args.senderUserUuid, }) logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx?.toString()) - if (pendingTx && pendingTx.amount.toString() === amount.toString() && pendingTx.memo === memo) { + if ( + pendingTx && + pendingTx.amount.toString() === args.amount.toString() && + pendingTx.memo === args.memo + ) { logger.debug('XCom: settleSendCoins matching pendingTX for settlement...') await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx) @@ -236,49 +240,40 @@ export class SendCoinsResolver { logger.debug('XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...') throw new LogError( `Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`, - recipientCommunityUuid, - recipientUserIdentifier, + args.recipientCommunityUuid, + args.recipientUserIdentifier, PendingTransactionState.NEW, TransactionTypeId.RECEIVE, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, + args.creationDate, + args.amount, + args.memo, + args.senderCommunityUuid, + args.senderUserUuid, + args.senderUserName, ) } } @Mutation(() => Boolean) async revertSettledSendCoins( - @Args() - { - recipientCommunityUuid, - recipientUserIdentifier, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, - }: SendCoinsArgs, + @Arg('data') + args: SendCoinsArgs, ): Promise { logger.debug(`revertSettledSendCoins() via apiVersion=1_0 ...`) // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ - communityUuid: recipientCommunityUuid, + communityUuid: args.recipientCommunityUuid, }) if (!homeCom) { throw new LogError( `revertSettledSendCoins with wrong recipientCommunityUuid`, - recipientCommunityUuid, + args.recipientCommunityUuid, ) } let receiverUser try { // second check if receiver user exists in this community - receiverUser = await findUserByIdentifier(recipientUserIdentifier) + receiverUser = await findUserByIdentifier(args.recipientUserIdentifier) } catch (err) { logger.error('Error in findUserByIdentifier:', err) throw new LogError( @@ -287,16 +282,20 @@ export class SendCoinsResolver { ) } const pendingTx = await DbPendingTransaction.findOneBy({ - userCommunityUuid: recipientCommunityUuid, - userGradidoID: receiverUser.gradidoID, + userCommunityUuid: args.recipientCommunityUuid, + userGradidoID: args.recipientUserIdentifier, state: PendingTransactionState.SETTLED, typeId: TransactionTypeId.RECEIVE, - balanceDate: new Date(creationDate), - linkedUserCommunityUuid: senderCommunityUuid, - linkedUserGradidoID: senderUserUuid, + balanceDate: new Date(args.creationDate), + linkedUserCommunityUuid: args.senderCommunityUuid, + linkedUserGradidoID: args.senderUserUuid, }) logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx) - if (pendingTx && pendingTx.amount.toString() === amount.toString() && pendingTx.memo === memo) { + if ( + pendingTx && + pendingTx.amount.toString() === args.amount.toString() && + pendingTx.memo === args.memo + ) { logger.debug('XCom: revertSettledSendCoins matching pendingTX for remove...') try { await revertSettledReceiveTransaction(homeCom, receiverUser, pendingTx) @@ -308,16 +307,16 @@ export class SendCoinsResolver { logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...') throw new LogError( `Can't find in revertSettledSendCoins the pending receiver TX for args=`, - recipientCommunityUuid, - recipientUserIdentifier, + args.recipientCommunityUuid, + args.recipientUserIdentifier, PendingTransactionState.SETTLED, TransactionTypeId.RECEIVE, - creationDate, - amount, - memo, - senderCommunityUuid, - senderUserUuid, - senderUserName, + args.creationDate, + args.amount, + args.memo, + args.senderCommunityUuid, + args.senderUserUuid, + args.senderUserName, ) } logger.debug(`revertSendCoins()-1_0... successfull`) diff --git a/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts index 6eb933f6a..4b0f989ba 100644 --- a/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts @@ -60,14 +60,31 @@ export async function revertSettledReceiveTransaction( } const lastTransaction = await getLastTransaction(receiverUser.id) + logger.debug(`LastTransaction vs PendingTransaction`) + logger.debug(`balance:`, lastTransaction?.balance.toString(), pendingTx.balance.toString()) + logger.debug( + `balanceDate:`, + lastTransaction?.balanceDate.toISOString(), + pendingTx.balanceDate.toISOString(), + ) + logger.debug(`GradidoID:`, lastTransaction?.userGradidoID, pendingTx.userGradidoID) + logger.debug(`Name:`, lastTransaction?.userName, pendingTx.userName) + logger.debug(`amount:`, lastTransaction?.amount.toString(), pendingTx.amount.toString()) + logger.debug(`memo:`, lastTransaction?.memo, pendingTx.memo) + logger.debug( + `linkedUserGradidoID:`, + lastTransaction?.linkedUserGradidoID, + pendingTx.linkedUserGradidoID, + ) + logger.debug(`linkedUserName:`, lastTransaction?.linkedUserName, pendingTx.linkedUserName) // now the last Tx must be the equivalant to the pendingTX if ( lastTransaction && - lastTransaction.balance === pendingTx.balance && + lastTransaction.balance.comparedTo(pendingTx.balance) === 0 && lastTransaction.balanceDate.toISOString() === pendingTx.balanceDate.toISOString() && lastTransaction.userGradidoID === pendingTx.userGradidoID && lastTransaction.userName === pendingTx.userName && - lastTransaction.amount.toString() === pendingTx.amount.toString() && + lastTransaction.amount.comparedTo(pendingTx.amount) === 0 && lastTransaction.memo === pendingTx.memo && lastTransaction.linkedUserGradidoID === pendingTx.linkedUserGradidoID && lastTransaction.linkedUserName === pendingTx.linkedUserName diff --git a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts index 5c522061c..e0e600be9 100644 --- a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts @@ -77,14 +77,6 @@ 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}`, - ) - } transactionReceive.balance = receiveBalance ? receiveBalance.balance : pendingTx.amount transactionReceive.balanceDate = pendingTx.balanceDate transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)