From 5ecb79d867500e9654c7d674e4b57819aeaf9d0c Mon Sep 17 00:00:00 2001 From: David May <85513542+davidleomay@users.noreply.github.com> Date: Thu, 15 Jan 2026 11:29:03 +0100 Subject: [PATCH 1/3] fix: fixed circular update dependency (#2943) * fix: fixed circular update dependency * fix: remove unused assignment in trySetMail --- .../generic/kyc/services/kyc.service.ts | 3 ++- .../user/models/user-data/user-data.service.ts | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/subdomains/generic/kyc/services/kyc.service.ts b/src/subdomains/generic/kyc/services/kyc.service.ts index 6064e6d09a..4808d38183 100644 --- a/src/subdomains/generic/kyc/services/kyc.service.ts +++ b/src/subdomains/generic/kyc/services/kyc.service.ts @@ -1170,7 +1170,8 @@ export class KycService { async trySetMail(user: UserData, step: KycStep, mail: string): Promise> { try { - user = await this.userDataService.trySetUserMail(user, mail); + // skipKycInit=true: we're already in the KYC flow + await this.userDataService.trySetUserMail(user, mail, true); return step.complete({ mail }); } catch (e) { const error = (e as Error).message?.includes('account merge request sent') diff --git a/src/subdomains/generic/user/models/user-data/user-data.service.ts b/src/subdomains/generic/user/models/user-data/user-data.service.ts index eff8ad313c..a32a7aed1a 100644 --- a/src/subdomains/generic/user/models/user-data/user-data.service.ts +++ b/src/subdomains/generic/user/models/user-data/user-data.service.ts @@ -601,13 +601,13 @@ export class UserDataService { await this.checkMail(userData, cacheEntry.mail); - return this.doUpdateUserMail(userData, cacheEntry.mail); + return this.doUpdateUserMail(userData, cacheEntry.mail, false); } - async trySetUserMail(userData: UserData, mail: string): Promise { + async trySetUserMail(userData: UserData, mail: string, skipKycInit = false): Promise { await this.checkMail(userData, mail); - return this.doUpdateUserMail(userData, mail); + return this.doUpdateUserMail(userData, mail, skipKycInit); } async checkMail(userData: UserData, mail: string): Promise { @@ -630,7 +630,7 @@ export class UserDataService { throw new ConflictException(errorMessage); } - private async doUpdateUserMail(userData: UserData, mail: string): Promise { + private async doUpdateUserMail(userData: UserData, mail: string, skipKycInit: boolean): Promise { await this.userDataRepo.update(userData.id, { mail }); Object.assign(userData, { mail }); @@ -647,10 +647,12 @@ export class UserDataService { await this.kycLogService.createMailChangeLog(userData, userData.mail, mail); - try { - await this.kycService.initializeProcess(userData); - } catch (e) { - this.logger.error(`Failed to initialize KYC process for account ${userData.id}:`, e); + if (!skipKycInit) { + try { + await this.kycService.initializeProcess(userData); + } catch (e) { + this.logger.error(`Failed to initialize KYC process for account ${userData.id}:`, e); + } } return userData; From 043dfc60b32fd2b529e5e4d98ac18ae1f2995864 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Thu, 15 Jan 2026 11:50:47 +0100 Subject: [PATCH 2/3] fix: skip input mail for Bitcoin purchases with txId (#2941) * fix: skip input mail for Bitcoin purchases with txId When a Bitcoin purchase already has a txId set (payout already executed), skip the 'Einzahlung eingetroffen' mail and only send the 'BuyCryptoCompleted' mail directly. This prevents users from receiving two mails in quick succession for fast Bitcoin transactions. * style: fix prettier formatting --- .../payment/services/transaction-notification.service.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/subdomains/supporting/payment/services/transaction-notification.service.ts b/src/subdomains/supporting/payment/services/transaction-notification.service.ts index 18105811e9..586b37569b 100644 --- a/src/subdomains/supporting/payment/services/transaction-notification.service.ts +++ b/src/subdomains/supporting/payment/services/transaction-notification.service.ts @@ -43,7 +43,7 @@ export class TransactionNotificationService { }, relations: { bankTx: true, - buyCrypto: true, + buyCrypto: { buy: { asset: true } }, buyFiat: true, userData: { wallet: true }, user: { wallet: true }, @@ -59,6 +59,12 @@ export class TransactionNotificationService { ) continue; + // Skip input mail for Bitcoin purchases that already have txId (will receive BuyCryptoCompleted mail directly) + if (entity.buyCrypto?.txId && entity.buyCrypto?.buy?.asset?.uniqueName === 'Bitcoin/BTC') { + await this.repo.update(...entity.mailSent()); + continue; + } + if (entity.userData?.mail) await this.notificationService.sendMail({ type: MailType.USER_V2, From 01ad0f1ec0cbf1932a556963eeefcb9654eecb74 Mon Sep 17 00:00:00 2001 From: David May <85513542+davidleomay@users.noreply.github.com> Date: Thu, 15 Jan 2026 12:20:50 +0100 Subject: [PATCH 3/3] Improve circular dependency fix (#2945) * fix: fixed circular update dependency * fix: remove unused assignment in trySetMail * fix: improved circular fix --- .../generic/kyc/services/kyc.service.ts | 5 +++-- .../user/models/user-data/user-data.service.ts | 18 ++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/subdomains/generic/kyc/services/kyc.service.ts b/src/subdomains/generic/kyc/services/kyc.service.ts index 4808d38183..6006338b92 100644 --- a/src/subdomains/generic/kyc/services/kyc.service.ts +++ b/src/subdomains/generic/kyc/services/kyc.service.ts @@ -1170,8 +1170,9 @@ export class KycService { async trySetMail(user: UserData, step: KycStep, mail: string): Promise> { try { - // skipKycInit=true: we're already in the KYC flow - await this.userDataService.trySetUserMail(user, mail, true); + if (user.mail !== mail) { + await this.userDataService.trySetUserMail(user, mail); + } return step.complete({ mail }); } catch (e) { const error = (e as Error).message?.includes('account merge request sent') diff --git a/src/subdomains/generic/user/models/user-data/user-data.service.ts b/src/subdomains/generic/user/models/user-data/user-data.service.ts index a32a7aed1a..eff8ad313c 100644 --- a/src/subdomains/generic/user/models/user-data/user-data.service.ts +++ b/src/subdomains/generic/user/models/user-data/user-data.service.ts @@ -601,13 +601,13 @@ export class UserDataService { await this.checkMail(userData, cacheEntry.mail); - return this.doUpdateUserMail(userData, cacheEntry.mail, false); + return this.doUpdateUserMail(userData, cacheEntry.mail); } - async trySetUserMail(userData: UserData, mail: string, skipKycInit = false): Promise { + async trySetUserMail(userData: UserData, mail: string): Promise { await this.checkMail(userData, mail); - return this.doUpdateUserMail(userData, mail, skipKycInit); + return this.doUpdateUserMail(userData, mail); } async checkMail(userData: UserData, mail: string): Promise { @@ -630,7 +630,7 @@ export class UserDataService { throw new ConflictException(errorMessage); } - private async doUpdateUserMail(userData: UserData, mail: string, skipKycInit: boolean): Promise { + private async doUpdateUserMail(userData: UserData, mail: string): Promise { await this.userDataRepo.update(userData.id, { mail }); Object.assign(userData, { mail }); @@ -647,12 +647,10 @@ export class UserDataService { await this.kycLogService.createMailChangeLog(userData, userData.mail, mail); - if (!skipKycInit) { - try { - await this.kycService.initializeProcess(userData); - } catch (e) { - this.logger.error(`Failed to initialize KYC process for account ${userData.id}:`, e); - } + try { + await this.kycService.initializeProcess(userData); + } catch (e) { + this.logger.error(`Failed to initialize KYC process for account ${userData.id}:`, e); } return userData;