From 6a6967561064fb7779197275ec12fc048678d1f7 Mon Sep 17 00:00:00 2001 From: Yannick <52333989+Yannick1712@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:58:03 +0100 Subject: [PATCH 1/2] [NOTASK] set wallet with merge (#3286) * [NOTASK] set wallet with merge * [NOTASK] set user ref with existing ref * [NOTASK] Refactoring --- src/config/config.ts | 1 + .../core/custody/services/custody.service.ts | 2 +- .../models/user-data/user-data.service.ts | 1 + .../generic/user/models/user/user.service.ts | 21 +++++++++++-------- .../user/models/wallet/wallet.service.ts | 3 ++- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/config/config.ts b/src/config/config.ts index 43dde35fb4..795712f8f0 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -47,6 +47,7 @@ export class Configuration { kycVersion: Version = '2'; defaultVersionString = `v${this.defaultVersion}`; defaultRef = '000-000'; + defaultWalletId = 1; transactionRefundExpirySeconds = 300; // 5 minutes - enough time to fill out the refund form refRewardManualCheckLimit = 3000; // EUR txRequestWaitingExpiryDays = 7; diff --git a/src/subdomains/core/custody/services/custody.service.ts b/src/subdomains/core/custody/services/custody.service.ts index e375233e68..e131e117da 100644 --- a/src/subdomains/core/custody/services/custody.service.ts +++ b/src/subdomains/core/custody/services/custody.service.ts @@ -54,7 +54,7 @@ export class CustodyService { const custodyWallet = EvmUtil.createWallet(Config.blockchain.evm.custodyAccount(addressIndex)); const signature = await custodyWallet.signMessage(Config.auth.signMessageGeneral + custodyWallet.address); - const account = await this.userDataService.getUserData(accountId); + const account = await this.userDataService.getUserData(accountId, { users: true }); if (!account) throw new NotFoundException('User not found'); const custodyUser = await this.userService.createUser( 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 0f2193c108..e4a55f545b 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 @@ -1166,6 +1166,7 @@ export class UserDataService { // optional master updates if (master.status === UserDataStatus.KYC_ONLY && slave.users.length && slave.wallet) master.wallet = slave.wallet; if ([UserDataStatus.KYC_ONLY, UserDataStatus.DEACTIVATED].includes(master.status)) master.status = slave.status; + if ((!master.wallet || master.wallet.id === Config.defaultWalletId) && slave.wallet) master.wallet = slave.wallet; if (!master.amlListAddedDate && slave.amlListAddedDate) { master.amlListAddedDate = slave.amlListAddedDate; master.amlListExpiredDate = slave.amlListExpiredDate; diff --git a/src/subdomains/generic/user/models/user/user.service.ts b/src/subdomains/generic/user/models/user/user.service.ts index bb0a5147be..be1beb2a86 100644 --- a/src/subdomains/generic/user/models/user/user.service.ts +++ b/src/subdomains/generic/user/models/user/user.service.ts @@ -240,11 +240,14 @@ export class UserService { addressType: CryptoService.getAddressType(data.address), }); const userIsActive = data.userData?.status === UserDataStatus.ACTIVE; + const lastExistingUsedRef = data.userData?.users + ? Util.sort(data.userData.users, 'id', 'DESC').find((u) => u.usedRef !== Config.defaultRef)?.usedRef + : undefined; user.ip = data.ip; user.ipCountry = this.geoLocationService.getCountry(data.ip); user.wallet = data.wallet ?? (await this.walletService.getDefault()); - user.usedRef = await this.checkRef(user, data.usedRef); + user.usedRef = await this.checkRef(user, data.usedRef, lastExistingUsedRef); user.origin = data.origin; user.custodyProvider = data.custodyProvider; if (userIsActive) user.status = UserStatus.ACTIVE; @@ -597,14 +600,14 @@ export class UserService { await this.userDataRepo.activateUserData(userData); } - private async checkRef(user: User, usedRef: string): Promise { - const refUser = await this.getRefUser(usedRef); - return usedRef === null || - usedRef === user.ref || - (usedRef && !refUser) || - user?.userData?.id === refUser?.userData?.id - ? Config.defaultRef - : usedRef; + private async checkRef(user: User, usedRef?: string, existingUsedRef?: string): Promise { + if (usedRef) { + const refUser = await this.getRefUser(usedRef); + const isValidRef = usedRef !== user.ref && refUser && user?.userData?.id !== refUser?.userData?.id; + if (isValidRef) return usedRef; + } + + return existingUsedRef ?? Config.defaultRef; } public async getTotalRefRewards(): Promise { diff --git a/src/subdomains/generic/user/models/wallet/wallet.service.ts b/src/subdomains/generic/user/models/wallet/wallet.service.ts index 966e499314..068aa02508 100644 --- a/src/subdomains/generic/user/models/wallet/wallet.service.ts +++ b/src/subdomains/generic/user/models/wallet/wallet.service.ts @@ -1,4 +1,5 @@ import { Injectable, NotFoundException } from '@nestjs/common'; +import { Config } from 'src/config/config'; import { WalletRepository } from 'src/subdomains/generic/user/models/wallet/wallet.repository'; import { FindOptionsRelations } from 'typeorm'; import { WalletDto } from './dto/wallet.dto'; @@ -40,6 +41,6 @@ export class WalletService { } async getDefault(): Promise { - return this.repo.findOneCachedBy('default', { id: 1 }); + return this.repo.findOneCachedBy('default', { id: Config.defaultWalletId }); } } From 5b17bc80ceef0d395d8a530481923b1be315fd06 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:00:54 +0100 Subject: [PATCH 2/2] fix: recalibrate financeLogPairIds toScrypt EUR (2nd) (#3357) Receiver side includes MaerkiBaumann exchange_tx deposits that are excluded from the sender side (filtered by eurBankIbans), causing a 281k EUR mismatch and negative toScryptUnfiltered. This hides all Scrypt EUR pending balances including the legitimate 30k transfer. Move pair IDs forward to bankTxId 191523 / exchangeTxId 126558 to exclude orphan transactions from the calculation window. --- ...72600000000-RecalibrateScryptEurPairIds.js | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 migration/1772600000000-RecalibrateScryptEurPairIds.js diff --git a/migration/1772600000000-RecalibrateScryptEurPairIds.js b/migration/1772600000000-RecalibrateScryptEurPairIds.js new file mode 100644 index 0000000000..a9ff1fd8e5 --- /dev/null +++ b/migration/1772600000000-RecalibrateScryptEurPairIds.js @@ -0,0 +1,88 @@ +/** + * @typedef {import('typeorm').MigrationInterface} MigrationInterface + * @typedef {import('typeorm').QueryRunner} QueryRunner + */ + +/** + * Recalibrate financeLogPairIds for toScrypt EUR (second recalibration). + * + * The receiver side (eurReceiverScryptExchangeTx) includes ALL Scrypt EUR deposits, + * while the sender side (eurSenderScryptBankTx) is filtered by eurBankIbans (Olkypay + + * Yapeal only). Former MaerkiBaumann transfers (bank_tx 191068: 363k, 191069: 42k) + * created exchange_tx deposits but are excluded from the bank_tx sender list, causing + * a 281k EUR mismatch and a negative toScryptUnfiltered. + * + * Fix: Move the pair IDs forward to the latest settled pair: + * bankTxId 191523 (30k EUR, Olkypay, Mar 4) + * exchangeTxId 126558 (30k EUR, Scrypt DEPOSIT, Mar 4) + * + * This excludes orphan exchange_tx and MaerkiBaumann bank_tx from the window, + * correctly showing only the pending 30k EUR transfer. + * + * @class + * @implements {MigrationInterface} + */ +module.exports = class RecalibrateScryptEurPairIds1772600000000 { + name = 'RecalibrateScryptEurPairIds1772600000000'; + + /** + * @param {QueryRunner} queryRunner + */ + async up(queryRunner) { + console.log('=== Recalibrate financeLogPairIds toScrypt EUR (2nd) ===\n'); + + const rows = await queryRunner.query( + `SELECT id, value FROM dbo.setting WHERE [key] = 'financeLogPairIds'`, + ); + + if (rows.length === 0) { + console.log('ERROR: financeLogPairIds setting not found. Aborting.'); + return; + } + + const setting = rows[0]; + const pairIds = JSON.parse(setting.value); + + console.log('Current toScrypt.eur:', JSON.stringify(pairIds.toScrypt.eur)); + + pairIds.toScrypt.eur.bankTxId = 191523; + pairIds.toScrypt.eur.exchangeTxId = 126558; + + console.log('New toScrypt.eur:', JSON.stringify(pairIds.toScrypt.eur)); + + const newValue = JSON.stringify(pairIds); + + await queryRunner.query( + `UPDATE dbo.setting SET value = '${newValue}' WHERE id = ${setting.id}`, + ); + + // Verify + const verify = await queryRunner.query( + `SELECT value FROM dbo.setting WHERE id = ${setting.id}`, + ); + const verified = JSON.parse(verify[0].value); + console.log('\nVerified toScrypt.eur:', JSON.stringify(verified.toScrypt.eur)); + console.log('\n=== Migration Complete ==='); + } + + /** + * @param {QueryRunner} queryRunner + */ + async down(queryRunner) { + const rows = await queryRunner.query( + `SELECT id, value FROM dbo.setting WHERE [key] = 'financeLogPairIds'`, + ); + + if (rows.length === 0) return; + + const setting = rows[0]; + const pairIds = JSON.parse(setting.value); + + pairIds.toScrypt.eur.bankTxId = 190029; + pairIds.toScrypt.eur.exchangeTxId = 123655; + + await queryRunner.query( + `UPDATE dbo.setting SET value = '${JSON.stringify(pairIds)}' WHERE id = ${setting.id}`, + ); + } +};