diff --git a/backend/src/federation/client/1_0/query/revertSendCoins.ts b/backend/src/federation/client/1_0/query/revertSendCoins.ts index 63c3cff63..881107cb4 100644 --- a/backend/src/federation/client/1_0/query/revertSendCoins.ts +++ b/backend/src/federation/client/1_0/query/revertSendCoins.ts @@ -4,7 +4,7 @@ export const revertSendCoins = gql` mutation ( $communityReceiverIdentifier: String! $userReceiverIdentifier: String! - $creationDate: Date! + $creationDate: String! $amount: Decimal! $memo: String! $communitySenderIdentifier: String! 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 a9ea7e068..7b580b240 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.test.ts @@ -65,6 +65,29 @@ describe('SendCoinsResolver', () => { ) } ` + const revertSendCoinsMutation = ` + mutation ( + $communityReceiverIdentifier: String! + $userReceiverIdentifier: String! + $creationDate: String! + $amount: Decimal! + $memo: String! + $communitySenderIdentifier: String! + $userSenderIdentifier: String! + $userSenderName: String! + ) { + revertSendCoins( + communityReceiverIdentifier: $communityReceiverIdentifier + userReceiverIdentifier: $userReceiverIdentifier + creationDate: $creationDate + amount: $amount + memo: $memo + communitySenderIdentifier: $communitySenderIdentifier + userSenderIdentifier: $userSenderIdentifier + userSenderName: $userSenderName + ) + } +` describe('voteForSendCoins', () => { let homeCom: DbCommunity @@ -190,4 +213,144 @@ describe('SendCoinsResolver', () => { }) }) }) + + describe('revertSendCoins', () => { + let homeCom: DbCommunity + let foreignCom: DbCommunity + let sendUser: DbUser + let recipUser: DbUser + const creationDate = new Date() + + beforeEach(async () => { + await cleanDB() + homeCom = DbCommunity.create() + homeCom.foreign = false + homeCom.url = 'homeCom-url' + homeCom.name = 'homeCom-Name' + homeCom.description = 'homeCom-Description' + homeCom.creationDate = new Date() + homeCom.publicKey = Buffer.from('homeCom-publicKey') + homeCom.communityUuid = 'homeCom-UUID' + await DbCommunity.insert(homeCom) + + foreignCom = DbCommunity.create() + foreignCom.foreign = true + foreignCom.url = 'foreignCom-url' + foreignCom.name = 'foreignCom-Name' + foreignCom.description = 'foreignCom-Description' + foreignCom.creationDate = new Date() + foreignCom.publicKey = Buffer.from('foreignCom-publicKey') + foreignCom.communityUuid = 'foreignCom-UUID' + await DbCommunity.insert(foreignCom) + + sendUser = DbUser.create() + sendUser.alias = 'sendUser-alias' + sendUser.firstName = 'sendUser-FirstName' + sendUser.gradidoID = 'sendUser-GradidoID' + sendUser.lastName = 'sendUser-LastName' + await DbUser.insert(sendUser) + + recipUser = DbUser.create() + recipUser.alias = 'recipUser-alias' + recipUser.firstName = 'recipUser-FirstName' + recipUser.gradidoID = 'recipUser-GradidoID' + recipUser.lastName = 'recipUser-LastName' + await DbUser.insert(recipUser) + + await mutate({ + mutation: voteForSendCoinsMutation, + variables: { + communityReceiverIdentifier: foreignCom.communityUuid, + userReceiverIdentifier: recipUser.gradidoID, + creationDate: creationDate.toISOString(), + amount: 100, + memo: 'X-Com-TX memo', + communitySenderIdentifier: homeCom.communityUuid, + userSenderIdentifier: sendUser.gradidoID, + userSenderName: fullName(sendUser.firstName, sendUser.lastName), + }, + }) + }) + + describe('unknown recipient community', () => { + it('throws an error', async () => { + jest.clearAllMocks() + expect( + await mutate({ + mutation: revertSendCoinsMutation, + variables: { + communityReceiverIdentifier: 'invalid foreignCom', + userReceiverIdentifier: recipUser.gradidoID, + creationDate: creationDate.toISOString(), + amount: 100, + memo: 'X-Com-TX memo', + communitySenderIdentifier: homeCom.communityUuid, + userSenderIdentifier: sendUser.gradidoID, + userSenderName: fullName(sendUser.firstName, sendUser.lastName), + }, + }), + ).toEqual( + expect.objectContaining({ + errors: [new GraphQLError('revertSendCoins with wrong communityReceiverIdentifier')], + }), + ) + }) + }) + + describe('unknown recipient user', () => { + it('throws an error', async () => { + jest.clearAllMocks() + expect( + await mutate({ + mutation: revertSendCoinsMutation, + variables: { + communityReceiverIdentifier: foreignCom.communityUuid, + userReceiverIdentifier: 'invalid recipient', + creationDate: creationDate.toISOString(), + amount: 100, + memo: 'X-Com-TX memo', + communitySenderIdentifier: homeCom.communityUuid, + userSenderIdentifier: sendUser.gradidoID, + userSenderName: fullName(sendUser.firstName, sendUser.lastName), + }, + }), + ).toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'revertSendCoins with unknown userReceiverIdentifier in the community=', + ), + ], + }), + ) + }) + }) + + describe('valid X-Com-TX reverted', () => { + it('throws an error', async () => { + jest.clearAllMocks() + expect( + await mutate({ + mutation: revertSendCoinsMutation, + variables: { + communityReceiverIdentifier: foreignCom.communityUuid, + userReceiverIdentifier: recipUser.gradidoID, + creationDate: creationDate.toISOString(), + amount: 100, + memo: 'X-Com-TX memo', + communitySenderIdentifier: homeCom.communityUuid, + userSenderIdentifier: sendUser.gradidoID, + userSenderName: fullName(sendUser.firstName, sendUser.lastName), + }, + }), + ).toEqual( + expect.objectContaining({ + data: { + revertSendCoins: true, + }, + }), + ) + }) + }) + }) }) diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index 7058c4b49..11222a3ce 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -58,6 +58,7 @@ export class SendCoinsResolver { 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 = communitySenderIdentifier pendingTx.linkedUserGradidoID = userSenderIdentifier pendingTx.linkedUserName = userSenderName @@ -94,36 +95,36 @@ export class SendCoinsResolver { }: SendCoinsArgs, ): Promise { logger.debug(`revertSendCoins() via apiVersion=1_0 ...`) + // first check if receiver community is correct + const homeCom = await DbCommunity.findOneBy({ + communityUuid: communityReceiverIdentifier, + }) + if (!homeCom) { + throw new LogError( + `revertSendCoins with wrong communityReceiverIdentifier`, + communityReceiverIdentifier, + ) + } + // second check if receiver user exists in this community + const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier }) + if (!receiverUser) { + throw new LogError( + `revertSendCoins with unknown userReceiverIdentifier in the community=`, + homeCom.name, + ) + } try { - // first check if receiver community is correct - const homeCom = await DbCommunity.findOneBy({ - communityUuid: communityReceiverIdentifier, - }) - if (!homeCom) { - throw new LogError( - `revertSendCoins with wrong communityReceiverIdentifier`, - communityReceiverIdentifier, - ) - } - // second check if receiver user exists in this community - const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier }) - if (!receiverUser) { - throw new LogError( - `revertSendCoins with unknown userReceiverIdentifier in the community=`, - homeCom.name, - ) - } const pendingTx = await DbPendingTransaction.findOneBy({ userCommunityUuid: communityReceiverIdentifier, userGradidoID: userReceiverIdentifier, state: PendingTransactionState.NEW, typeId: TransactionTypeId.RECEIVE, - balanceDate: creationDate, + balanceDate: new Date(creationDate), linkedUserCommunityUuid: communitySenderIdentifier, linkedUserGradidoID: userSenderIdentifier, }) logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx) - if (pendingTx && pendingTx.amount === amount) { + if (pendingTx && pendingTx.amount.toString() === amount.toString()) { logger.debug('XCom: revertSendCoins matching pendingTX for remove...') try { await pendingTx.remove() @@ -132,7 +133,11 @@ export class SendCoinsResolver { throw new LogError('Error in revertSendCoins on removing pendingTx of receiver: ', err) } } else { - logger.debug('XCom: revertSendCoins NOT matching pendingTX for remove...') + logger.debug( + 'XCom: revertSendCoins NOT matching pendingTX for remove:', + pendingTx?.amount, + amount, + ) throw new LogError( `Can't find in revertSendCoins the pending receiver TX for args=`, communityReceiverIdentifier,