From f020d860b7015bfc6b4e69a5d2ee1cca2dcbc255 Mon Sep 17 00:00:00 2001
From: clauspeterhuebner
Date: Tue, 22 Jul 2025 17:44:42 +0200
Subject: [PATCH] save current work
---
.../graphql/resolver/TransactionResolver.ts | 2 +-
.../resolver/util/processXComSendCoins.ts | 72 ++++---
.../api/1_0/resolver/SendCoinsResolver.ts | 194 +++++++++++-------
3 files changed, 159 insertions(+), 109 deletions(-)
diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts
index 67dcc4432..b3c2cf751 100644
--- a/backend/src/graphql/resolver/TransactionResolver.ts
+++ b/backend/src/graphql/resolver/TransactionResolver.ts
@@ -497,7 +497,7 @@ export class TransactionResolver {
recipientIdentifier,
)
logger.debug('processXComPendingSendCoins result: ', pendingResult)
- if (pendingResult.vote && pendingResult.recipGradidoID) {
+ if (pendingResult && pendingResult.vote && pendingResult.recipGradidoID) {
logger.debug('vor processXComCommittingSendCoins... ')
committingResult = await processXComCommittingSendCoins(
recipCom,
diff --git a/backend/src/graphql/resolver/util/processXComSendCoins.ts b/backend/src/graphql/resolver/util/processXComSendCoins.ts
index fa50d3353..2b153e180 100644
--- a/backend/src/graphql/resolver/util/processXComSendCoins.ts
+++ b/backend/src/graphql/resolver/util/processXComSendCoins.ts
@@ -16,7 +16,7 @@ import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0
import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs'
import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult'
import { SendCoinsClientFactory } from '@/federation/client/SendCoinsClientFactory'
-import { encryptAndSign, PendingTransactionState, SendCoinsResponseJwtPayloadType, verifyAndDecrypt } from 'shared'
+import { encryptAndSign, PendingTransactionState, SendCoinsJwtPayloadType, SendCoinsResponseJwtPayloadType, verifyAndDecrypt } from 'shared'
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { LogError } from '@/server/LogError'
@@ -27,10 +27,10 @@ import { getLogger } from 'log4js'
import { settlePendingSenderTransaction } from './settlePendingSenderTransaction'
import { SendCoinsArgsLoggingView } from '@/federation/client/1_0/logging/SendCoinsArgsLogging.view'
import { SendCoinsResultLoggingView } from '@/federation/client/1_0/logging/SendCoinsResultLogging.view'
-import { EncryptedTransferArgs, SendCoinsJwtPayloadType } from 'core'
+import { EncryptedTransferArgs } from 'core'
import { randombytes_random } from 'sodium-native'
-const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.processXComSendCoins`)
+const createLogger = (method: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.processXComSendCoins.${method}`)
export async function processXComPendingSendCoins(
receiverCom: DbCommunity,
@@ -40,10 +40,10 @@ export async function processXComPendingSendCoins(
memo: string,
sender: dbUser,
recipientIdentifier: string,
-): Promise {
+): Promise {
let voteResult: SendCoinsResponseJwtPayloadType
+ const methodLogger = createLogger(`processXComPendingSendCoins`)
try {
- const methodLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.processXComSendCoins.processXComPendingSendCoins`)
// even if debug is not enabled, attributes are processed so we skip the entire call for performance reasons
if(methodLogger.isDebugEnabled()) {
methodLogger.debug(
@@ -58,16 +58,18 @@ export async function processXComPendingSendCoins(
)
}
if (await countOpenPendingTransactions([sender.gradidoID, recipientIdentifier]) > 0) {
- throw new LogError(
- `There exist still ongoing 'Pending-Transactions' for the involved users on sender-side!`,
- )
+ const errmsg = `There exist still ongoing 'Pending-Transactions' for the involved users on sender-side!`
+ methodLogger.error(errmsg)
+ throw new LogError(errmsg)
}
const handshakeID = randombytes_random().toString()
methodLogger.addContext('handshakeID', handshakeID)
// 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)
+ const errmsg = `User has not enough GDD or amount is < 0`
+ methodLogger.error(errmsg)
+ throw new LogError(errmsg)
}
if(methodLogger.isDebugEnabled()) {
methodLogger.debug(`calculated senderBalance = ${JSON.stringify(senderBalance, null, 2)}`)
@@ -83,12 +85,12 @@ export async function processXComPendingSendCoins(
if (client instanceof V1_0_SendCoinsClient) {
const payload = new SendCoinsJwtPayloadType(handshakeID,
- receiverCom.communityUuid,
+ receiverCom.communityUuid!,
recipientIdentifier,
creationDate.toISOString(),
amount,
memo,
- senderCom.communityUuid,
+ senderCom.communityUuid!,
sender.gradidoID,
fullName(sender.firstName, sender.lastName),
sender.alias
@@ -97,26 +99,33 @@ export async function processXComPendingSendCoins(
methodLogger.debug(`ready for voteForSendCoins with payload=${payload}`)
}
const jws = await encryptAndSign(payload, senderCom.privateJwtKey!, receiverCom.publicJwtKey!)
- methodLogger.debug('jws', jws)
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug('jws', jws)
+ }
// prepare the args for the client invocation
const args = new EncryptedTransferArgs()
args.publicKey = senderCom.publicKey.toString('hex')
args.jwt = jws
args.handshakeID = handshakeID
- methodLogger.debug('before client.voteForSendCoins() args:', args)
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug('before client.voteForSendCoins() args:', args)
+ }
const responseJwt = await client.voteForSendCoins(args)
- methodLogger.debug(`response of voteForSendCoins():`, responseJwt)
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(`response of voteForSendCoins():`, responseJwt)
+ }
if (responseJwt !== null) {
voteResult = await verifyAndDecrypt(handshakeID, responseJwt, senderCom.privateJwtKey!, receiverCom.publicJwtKey!) as SendCoinsResponseJwtPayloadType
- methodLogger.debug(`received payload from voteForSendCoins():`, voteResult)
- if (voteResult.tokentype !== SendCoinsResponseJwtPayloadType.SEND_COINS_RESPONSE_TYPE) {
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(`received payload from voteForSendCoins():`, voteResult)
+ }
+ if (voteResult && voteResult.tokentype !== SendCoinsResponseJwtPayloadType.SEND_COINS_RESPONSE_TYPE) {
const errmsg = `Invalid tokentype in voteForSendCoins-response of community with publicKey` + receiverCom.publicKey
methodLogger.error(errmsg)
- methodLogger.removeContext('handshakeID')
throw new Error('Error in X-Com-TX protocol...')
}
- if (voteResult.vote) {
+ if (voteResult && voteResult.vote) {
methodLogger.debug('prepare pendingTransaction for sender...')
// writing the pending transaction on receiver-side was successfull, so now write the sender side
try {
@@ -160,33 +169,30 @@ export async function processXComPendingSendCoins(
if (await client.revertSendCoins(args)) {
methodLogger.debug(`revertSendCoins()-1_0... successfull after revertCount=${revertCount}`)
// treat revertingSendCoins as an error of the whole sendCoins-process
- throw new LogError('Error in writing sender pending transaction: ', err)
+ const errmsg = `Error in writing sender pending transaction: ${JSON.stringify(err, null, 2)}`
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
} while (CONFIG.FEDERATION_XCOM_MAXREPEAT_REVERTSENDCOINS > revertCount++)
- throw new LogError(
- `Error in reverting receiver pending transaction even after revertCount=${revertCount}`,
- err,
- )
+ const errmsg = `Error in reverting receiver pending transaction even after revertCount=${revertCount}` + JSON.stringify(err, null, 2)
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
methodLogger.debug('voteForSendCoins()-1_0... successfull')
+ return voteResult
} else {
methodLogger.error(`break with error on writing pendingTransaction for recipient... ${voteResult}`)
}
- const result = new SendCoinsResult()
- result.vote = voteResult.vote
- result.recipGradidoID = voteResult.recipGradidoID
- result.recipFirstName = voteResult.recipFirstName
- result.recipLastName = voteResult.recipLastName
- result.recipAlias = voteResult.recipAlias
- return result
} else {
methodLogger.error(`break with no response from voteForSendCoins()-1_0...`)
}
}
- } catch (err: any) {
- throw new LogError(`Error: ${err.message}`, err)
+ } catch (err: any) {
+ const errmsg = `Error: ${err.message}` + JSON.stringify(err, null, 2)
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
- return new SendCoinsResult()
+ return null
}
export async function processXComCommittingSendCoins(
diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts
index 35850fc3e..bb04808a7 100644
--- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts
+++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts
@@ -10,159 +10,203 @@ import Decimal from 'decimal.js-light'
import { getLogger } from 'log4js'
import { Arg, Mutation, Resolver } from 'type-graphql'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
-import { PendingTransactionState } from 'shared'
+import { encryptAndSign, PendingTransactionState } from 'shared'
import { TransactionTypeId } from '../enum/TransactionTypeId'
import { SendCoinsArgsLoggingView } from '../logger/SendCoinsArgsLogging.view'
import { SendCoinsArgs } from '../model/SendCoinsArgs'
-import { SendCoinsResult } from '../model/SendCoinsResult'
+import { SendCoinsResponseJwtPayloadType } from 'shared'
import { calculateRecipientBalance } from '../util/calculateRecipientBalance'
// import { checkTradingLevel } from '@/graphql/util/checkTradingLevel'
import { revertSettledReceiveTransaction } from '../util/revertSettledReceiveTransaction'
import { settlePendingReceiveTransaction } from '../util/settlePendingReceiveTransaction'
import { storeForeignUser } from '../util/storeForeignUser'
import { countOpenPendingTransactions } from 'database'
-const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.api.1_0.resolver.SendCoinsResolver`)
+import { EncryptedTransferArgs } from 'core'
+import { interpretEncryptedTransferArgs } from 'core'
+import { SendCoinsJwtPayloadType } from 'shared'
+const createLogger = (method: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.api.1_0.resolver.SendCoinsResolver.${method}`)
@Resolver()
export class SendCoinsResolver {
- @Mutation(() => SendCoinsResult)
+ @Mutation(() => String)
async voteForSendCoins(
@Arg('data')
- args: SendCoinsArgs,
- ): Promise {
- logger.debug(`voteForSendCoins() via apiVersion=1_0 ...`, new SendCoinsArgsLoggingView(args))
- const result = new SendCoinsResult()
+ args: EncryptedTransferArgs,
+ ): Promise {
+ const methodLogger = createLogger(`voteForSendCoins`)
+ methodLogger.addContext('handshakeID', args.handshakeID)
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(`voteForSendCoins() via apiVersion=1_0 ...`, args)
+ }
+ const authArgs = await interpretEncryptedTransferArgs(args) as SendCoinsJwtPayloadType
+ if (!authArgs) {
+ const errmsg = `invalid authentication payload of requesting community with publicKey` + authArgs.publicKey
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
+ }
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(`voteForSendCoins() via apiVersion=1_0 ...`, authArgs)
+ }
// first check if receiver community is correct
- const homeCom = await DbCommunity.findOneBy({
- communityUuid: args.recipientCommunityUuid,
+ const recipientCom = await DbCommunity.findOneBy({
+ communityUuid: authArgs.recipientCommunityUuid,
})
- if (!homeCom) {
- throw new LogError(
- `voteForSendCoins with wrong recipientCommunityUuid`,
- args.recipientCommunityUuid,
- )
+ if (!recipientCom) {
+ const errmsg = `voteForSendCoins with wrong recipientCommunityUuid` + authArgs.recipientCommunityUuid
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
+ }
+ const senderCom = await DbCommunity.findOneBy({
+ communityUuid: authArgs.senderCommunityUuid,
+ })
+ if (!senderCom) {
+ const errmsg = `voteForSendCoins with wrong senderCommunityUuid` + authArgs.senderCommunityUuid
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
let receiverUser
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(
- args.recipientUserIdentifier,
- args.recipientCommunityUuid,
+ authArgs.recipientUserIdentifier,
+ authArgs.recipientCommunityUuid,
)
if (!receiverUser) {
- logger.error('Error in findUserByIdentifier:')
- throw new LogError(
- `voteForSendCoins with unknown recipientUserIdentifier in the community=`,
- homeCom.name,
- )
+ const errmsg = `voteForSendCoins with unknown recipientUserIdentifier in the community=` + recipientCom.name
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
- if (await countOpenPendingTransactions([args.senderUserUuid, receiverUser.gradidoID]) > 0) {
- throw new LogError(
- `There exist still ongoing 'Pending-Transactions' for the involved users on receiver-side!`,
- )
+ if (await countOpenPendingTransactions([authArgs.senderUserUuid, receiverUser.gradidoID]) > 0) {
+ const errmsg = `There exist still ongoing 'Pending-Transactions' for the involved users on receiver-side!`
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
try {
- const txDate = new Date(args.creationDate)
- const receiveBalance = await calculateRecipientBalance(receiverUser.id, args.amount, txDate)
+ const txDate = new Date(authArgs.creationDate)
+ const receiveBalance = await calculateRecipientBalance(receiverUser.id, authArgs.amount, txDate)
const pendingTx = DbPendingTransaction.create()
- pendingTx.amount = args.amount
- pendingTx.balance = receiveBalance ? receiveBalance.balance : args.amount
+ pendingTx.amount = authArgs.amount
+ pendingTx.balance = receiveBalance ? receiveBalance.balance : authArgs.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 = args.senderCommunityUuid
- pendingTx.linkedUserGradidoID = args.senderUserUuid
- pendingTx.linkedUserName = args.senderUserName
- pendingTx.memo = args.memo
+ pendingTx.linkedUserCommunityUuid = authArgs.senderCommunityUuid
+ pendingTx.linkedUserGradidoID = authArgs.senderUserUuid
+ pendingTx.linkedUserName = authArgs.senderUserName
+ pendingTx.memo = authArgs.memo
pendingTx.previous = receiveBalance ? receiveBalance.lastTransactionId : null
pendingTx.state = PendingTransactionState.NEW
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.userId = receiverUser.id
- pendingTx.userCommunityUuid = args.recipientCommunityUuid
+ pendingTx.userCommunityUuid = authArgs.recipientCommunityUuid
pendingTx.userGradidoID = receiverUser.gradidoID
pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName)
await DbPendingTransaction.insert(pendingTx)
- result.vote = true
- result.recipFirstName = receiverUser.firstName
- result.recipLastName = receiverUser.lastName
- result.recipAlias = receiverUser.alias
- result.recipGradidoID = receiverUser.gradidoID
- logger.debug(`voteForSendCoins()-1_0... successfull`)
+ const responseArgs = new SendCoinsResponseJwtPayloadType(
+ authArgs.handshakeID,
+ true,
+ receiverUser.firstName,
+ receiverUser.lastName,
+ receiverUser.alias,
+ receiverUser.gradidoID,
+ )
+ const responseJwt = await encryptAndSign(responseArgs, recipientCom.privateJwtKey!, senderCom.publicJwtKey!)
+ methodLogger.debug(`voteForSendCoins()-1_0... successfull`)
+ return responseJwt
} catch (err) {
- throw new LogError(`Error in voteForSendCoins: `, err)
+ const errmsg = `Error in voteForSendCoins: ` + err
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
- return result
}
@Mutation(() => Boolean)
async revertSendCoins(
@Arg('data')
- args: SendCoinsArgs,
+ args: EncryptedTransferArgs,
): Promise {
- logger.debug(`revertSendCoins() via apiVersion=1_0 ...`)
+ const methodLogger = createLogger(`revertSendCoins`)
+ methodLogger.addContext('handshakeID', args.handshakeID)
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(`revertSendCoins() via apiVersion=1_0 ...`)
+ }
+ const authArgs = await interpretEncryptedTransferArgs(args) as SendCoinsJwtPayloadType
+ if (!authArgs) {
+ const errmsg = `invalid revertSendCoins payload of requesting community with publicKey` + args.publicKey
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
+ }
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(`revertSendCoins() via apiVersion=1_0 ...`, authArgs)
+ }
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
- communityUuid: args.recipientCommunityUuid,
+ communityUuid: authArgs.recipientCommunityUuid,
})
if (!homeCom) {
- throw new LogError(
- `revertSendCoins with wrong recipientCommunityUuid`,
- args.recipientCommunityUuid,
- )
+ const errmsg = `revertSendCoins with wrong recipientCommunityUuid` + authArgs.recipientCommunityUuid
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
let receiverUser
// second check if receiver user exists in this community
- receiverUser = await findUserByIdentifier(args.recipientUserIdentifier)
+ receiverUser = await findUserByIdentifier(authArgs.recipientUserIdentifier)
if (!receiverUser) {
- logger.error('Error in findUserByIdentifier')
- throw new LogError(
- `revertSendCoins with unknown recipientUserIdentifier in the community=`,
- homeCom.name,
- )
+ const errmsg = `revertSendCoins with unknown recipientUserIdentifier in the community=` + homeCom.name
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
try {
const pendingTx = await DbPendingTransaction.findOneBy({
- userCommunityUuid: args.recipientCommunityUuid,
+ userCommunityUuid: authArgs.recipientCommunityUuid,
userGradidoID: receiverUser.gradidoID,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
- balanceDate: new Date(args.creationDate),
- linkedUserCommunityUuid: args.senderCommunityUuid,
- linkedUserGradidoID: args.senderUserUuid,
+ balanceDate: new Date(authArgs.creationDate),
+ linkedUserCommunityUuid: authArgs.senderCommunityUuid,
+ linkedUserGradidoID: authArgs.senderUserUuid,
})
- logger.debug(
- 'XCom: revertSendCoins found pendingTX=',
- pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null',
- )
- if (pendingTx && pendingTx.amount.toString() === args.amount.toString()) {
- logger.debug('XCom: revertSendCoins matching pendingTX for remove...')
+ if(methodLogger.isDebugEnabled()) {
+ methodLogger.debug(
+ 'XCom: revertSendCoins found pendingTX=',
+ pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null',
+ )
+ }
+ if (pendingTx && pendingTx.amount.toString() === authArgs.amount.toString()) {
+ methodLogger.debug('XCom: revertSendCoins matching pendingTX for remove...')
try {
await pendingTx.remove()
- logger.debug('XCom: revertSendCoins pendingTX for remove successfully')
+ methodLogger.debug('XCom: revertSendCoins pendingTX for remove successfully')
} catch (err) {
- throw new LogError('Error in revertSendCoins on removing pendingTx of receiver: ', err)
+ const errmsg = `Error in revertSendCoins on removing pendingTx of receiver: ` + err
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
} else {
- logger.debug(
+ methodLogger.debug(
'XCom: revertSendCoins NOT matching pendingTX for remove:',
pendingTx?.amount.toString(),
- args.amount.toString(),
+ authArgs.amount.toString(),
)
- throw new LogError(`Can't find in revertSendCoins the pending receiver TX for `, {
- args: new SendCoinsArgsLoggingView(args),
+ const errmsg = `Can't find in revertSendCoins the pending receiver TX for ` + {
+ args: new SendCoinsArgsLoggingView(authArgs),
pendingTransactionState: PendingTransactionState.NEW,
transactionType: TransactionTypeId.RECEIVE,
- })
+ }
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
- logger.debug(`revertSendCoins()-1_0... successfull`)
+ methodLogger.debug(`revertSendCoins()-1_0... successfull`)
return true
} catch (err) {
- throw new LogError(`Error in revertSendCoins: `, err)
+ const errmsg = `Error in revertSendCoins: ` + err
+ methodLogger.error(errmsg)
+ throw new Error(errmsg)
}
}