-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add husky pre-commit hooks with lint-staged #2966
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* [DEV-4468] Poll only deposit inputs * Add transaction.uid and Yapeal accountServiceRef to compliance search (#2707) * Add transaction.uid and Yapeal accountServiceRef to compliance search - Add transactionUid pattern (T + 16 alphanumeric chars) to Config.formats - Add TRANSACTION_UID to ComplianceSearchType enum - Extend accountServiceRef pattern to support Yapeal format (32 hex chars) - Add TransactionService dependency to SupportService * [NOTASK] Small refactoring --------- Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> * Add local development setup with automatic mocking and fixes Infrastructure: - Add docker-compose.yml with MSSQL Server for local database - Add .env.local.example with minimal config (no secrets) - Add scripts/setup.js for one-command setup (npm run setup) Setup Script Features: - Generate 19 wallet seeds/keys securely on first run - Start API in background (logs to api.log, PID to .api.pid) - Wait for database tables and seed data - Register admin user via API and grant admin role - Seed deposit addresses directly in database Seed Data (migration/seed/): - Add CSV files for language, fiat, country, asset, bank, fee, price_rule - Run seed.js after app start to populate database - Add safety checks to prevent accidental production seeding Mock Mode (ENVIRONMENT=loc): - Mock external HTTP calls (Alchemy, Tatum, Sift, CoinGecko, SumSub) - Mock Azure Storage with in-memory storage - Skip Alchemy webhook creation in local mode - Add sepatools mock for IBAN validation Code Changes: - Extract static chain configs to src/config/chains.config.ts - Clean up .env.example (remove hardcoded URLs/chain IDs) - Add SQL_ENCRYPT=false support for Docker self-signed certs - Fix Gnosis config: remove undefined swap/quote contract addresses - Fix Gnosis service: don't destructure non-existent properties - Fix package.json scripts for Linux/Azure compatibility: * Remove Windows-specific "SET NODE_ENV=master&" command * Fix path from "dist/main" to "dist/src/main" * Makes scripts cross-platform compatible Documentation: - Update README with Local Development section - Document Quick Start, NPM scripts, Docker commands - Explain mock mode and what is/isn't mocked Bug Fixes: - Fixed Gnosis chain initialization crash (undefined swap addresses) - Fixed Azure deployment startup crash (Linux incompatible scripts) - Fixed PricingService fiatMap race condition in local development Testing: - All tests passing (396 tests) - Build successful - API starts without errors on both local and Azure - Cross-platform compatibility verified * Add buy-specific virtual IBAN support (#2685) * Add buy-specific virtual IBAN support - Add buyId relation to VirtualIban entity for asset-specific vIBANs - Add personalIbanEnabled flag to Asset entity - Add buySpecificIbanEnabled flag to Wallet entity - Auto-create vIBAN when requesting payment info for eligible assets - Assign incoming payments via vIBAN→Buy link (no remittanceInfo needed) - Update QR codes, GiroCodes and invoices to omit reference for buy-specific IBANs - Add unique index on (buyId, currencyId) for race condition protection - Limit to max 10 vIBANs per UserData (falls back to normal bank silently) - Fix cache invalidation consistency in VirtualIbanService * Add dedicated RealUnit buy endpoint with personal IBAN (#2686) * Add dedicated RealUnit buy endpoint with personal IBAN - Add PUT /realunit/paymentInfo endpoint for REALU purchases - Auto-create buy-specific vIBAN for each purchase request - Require KYC Level 50, RealUnit registration, and allowlist status - Return personal IBAN, estimated shares, and QR code for payment - No remittanceInfo needed (IBAN is unique per asset) * Restrict RealUnit buy currency to CHF and EUR only * Remove bank name from RealUnit payment info response * Use RealUnit company address as payment recipient * Use RealUnit config for recipient address * Return separate address fields in RealUnit payment info * Remove sepaInstant from RealUnit payment info response * Remove allowlist check from RealUnit payment info * Add fee/rate calculation to RealUnit payment info - Integrate TransactionHelper.getTxDetails() for fee calculation - Return fees, minVolume, maxVolume, exchangeRate, rate, priceSteps - Use estimatedAmount from transaction helper instead of brokerbot - Only generate QR code if isValid is true * Add TransactionRequest creation to RealUnit payment info - Import TransactionRequestService and create transaction request after building response - Add id and routeId fields to RealUnitPaymentInfoDto - Fix bankInfo type for Swiss QR code generation * Add minVolumeTarget and maxVolumeTarget to RealUnit payment info * Add timestamp to RealUnit payment info response * fix: verifyRealUnitRegistrationSignature used wrong value for verifyTypedData. * Allow RealUnit registration with unverified email (#2699) * Normalize email inputs to lowercase (#2695) - Add Util.toLowerCaseTrim for email input normalization - Apply @Transform(Util.toLowerCaseTrim) to all email input DTOs: - KycContactData, KycInputDataDto - AuthMailDto - UpdateUserDataDto, UpdateUserMailDto - CreateRecommendationDto - AktionariatRegistrationDto Fixes issue where users registering with mixed-case emails (e.g. Samuel.kullmann@...) had merge conflicts when later using lowercase variant (samuel.kullmann@...) * Allow RealUnit registration with unverified email - If userData.mail is NULL, try to set the submitted email - Email is rejected if already used by another user - Email is saved to userData.mail if available * Validate lowercase email instead of transforming - Replace @Transform(Util.toLowerCaseTrim) with @IsLowercase validation - Preserves original email for EIP-712 signature verification - Returns clear error message if email contains uppercase --------- Co-authored-by: TuanLamNguyen <xnguyen.lam@gmail.com> --------- Co-authored-by: TuanLamNguyen <xnguyen.lam@gmail.com> * Fix: Skip IP country mismatch check for crypto input buy crypto transactions (#2712) The IP_COUNTRY_MISMATCH check should only apply to bank and card transactions, not to crypto-to-crypto swaps where the user's location is less relevant for AML purposes. * Change reset() to set type PENDING instead of GSHEET (#2714) When a BankTx is reset, it should have type PENDING to properly reflect its state as an unprocessed transaction. * fix(mock): remove unused import and suppress console warning (#2713) - Remove unused HttpService import - Add eslint-disable comment for intentional console.log in local dev * [NOTASK] fix chargebackBankFee for buyCrypto * [NOTASK] fix multiAccountBankName merge bug * chore: combined dependency updates and security fixes (#2720) - Upgrade supertest from v6 to v7.1.3 - Add multer v2.0.0 override (security fix for CVE-2022-24434) - Add Jest forceExit config (fixes worker exit warning) - Upgrade ESLint from v8 to v9 with flat config - Upgrade prettier from v2 to v3 - Add uuid and semver overrides (security fixes) Backward compatibility maintained for ESLint by disabling new strict rules. * Fix: Only show failure reason when AML check is not passed (#2722) The transaction reason should only be derived from amlReason when amlCheck is in FAIL, PENDING, or GSHEET status. This prevents showing misleading failure reasons for transactions with passed AML checks. * [NO-TASK] Auto-generated migration * Improve account merge confirmation email (#2708) * Improve account merge confirmation email - Only show greeting when name is available - Remove unnecessary support warning text - Add button for consistent UX with login email - Remove closing translations from all languages * [NOTASK] Refactoring --------- Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> * Add bank account details to refund endpoint (#2681) * Add bank account details to refund endpoint - Extend RefundDataDto with name, address, houseNumber, zip, city, country, iban, bic - Extract bank details from BankTx entity in getRefundData - Add getBankTxFromRefundEntity helper method * Fix refund bank fee calculation Use flat 2x bankFixed fee (1 EUR/CHF per transaction) instead of variable chargebackBankFee calculation * Revert "Fix refund bank fee calculation" This reverts commit 734707b. * [NOTASK] Refactoring --------- Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> * [NO-TASK] Fixed BSC gateway URL * fix: replace DeFiChain with Bitcoin as default blockchain (#2726) DeFiChain should never be the default or fallback blockchain. Changed all occurrences where DeFiChain was used as default to Bitcoin: - Asset entity column default - CryptoService address fallback - Mock entities for tests * fix: use Bitcoin instead of DeFiChain in test for non-supported AssetCategory (#2727) * fix: remove DeFiChain signature verification, add address detection (#2728) - Removes DeFiChain signature verification from CryptoService - Adds isDefichainAddress() to correctly identify existing DeFiChain users - Adds DeFiChain signature comparison in AuthService for existing users - Removes fallback to Bitcoin for unknown addresses - Throws 'Unsupported blockchain address' for unrecognized address formats - Existing users verified via stored signature in database - New DeFiChain registrations not possible * fix: use Bitcoin instead of DeFiChain in liquidity-order factory test (#2729) * fix: replace DFI with active assets in mocks and tests (#2730) * Fix: Auto-generate EVM wallet addresses in setup script (#2731) Problem: Setup script generated WALLET_PRIVATE_KEY variables but not the corresponding WALLET_ADDRESS variables, causing runtime errors: TypeError: Cannot read properties of undefined (reading 'toHexString') Solution: Derive wallet address from private key using ethers.Wallet and automatically set all *_WALLET_ADDRESS environment variables. Missing variables that are now auto-generated: - ETH_WALLET_ADDRESS - SEPOLIA_WALLET_ADDRESS - BSC_WALLET_ADDRESS - OPTIMISM_WALLET_ADDRESS - BASE_WALLET_ADDRESS - ARBITRUM_WALLET_ADDRESS - POLYGON_WALLET_ADDRESS - GNOSIS_WALLET_ADDRESS - CITREA_TESTNET_WALLET_ADDRESS * refactor(bitcoin): replace DeFiChain packages with @btc-vision/bitcoin-rpc (#2732) - Remove @defichain/jellyfish-api-core, @defichain/jellyfish-api-jsonrpc, @defichain/jellyfish-network, @defichain/whale-api-client - Add @btc-vision/bitcoin-rpc for native Bitcoin Core RPC support - Define UTXO and NetworkName types locally - Use wallet gettransaction RPC to get tx fee (not getrawtransaction) - Pass address_type parameter correctly in createAddress - Add safeguard for undefined fee in payout completion - Replace BigNumber with number for balance handling - Add Jest mock for @btc-vision/bitcoin-rpc * feat(bitcoin): Add support for unconfirmed UTXOs with next-block filtering (#2673) * Add EIP-7702 delegation for token forwarding (#2702) * Add EIP-7702 delegation for token forwarding - Add Eip7702DelegationService using MetaMask's EIP7702StatelessDeleGator - Single TX instead of 2-TX flow (gas top-up + token transfer) - Support for ETH, Arbitrum, Optimism, Polygon, Base, BSC, Gnosis, Sepolia - Toggleable via EVM_DELEGATION_ENABLED config flag - Automatic fallback to legacy flow when disabled or chain not supported - Input validation for amount, recipient, and token contract address * Update Citrea Testnet explorer URL to citreascan.com * Use DelegationManager for EIP-7702 token transfers - Replace direct execute() call with redeemDelegations() via DelegationManager - Add EIP-712 delegation signing (Deposit -> Relayer) - Use ERC-7579 encodePacked format for execution data - Remove unused eip7702-stateless-delegator.abi.json - Add delegation-manager.abi.json with redeemDelegations ABI The MetaMask Delegator's execute() function has onlyEntryPointOrSelf access control. This change uses the DelegationManager contract instead, which allows any caller to redeem delegations with valid signatures. Flow: Relayer -> DelegationManager.redeemDelegations() -> Account.executeFromExecutor() Tested successfully on Ethereum mainnet: TX: 0x641da73a82691185612ff79d7e0d1b2d9bdc66d84e32455b58ddba7cec3d5a9a * Remove empty constructor to fix linter * Add comprehensive tests for EIP-7702 delegation service - Test isDelegationSupported for all 8 supported chains (ETH, ARB, OP, MATIC, BASE, BSC, GNO, SEP) - Test isDelegationSupported returns false for unsupported chains (BTC, LN, XMR, SOL, TRX, ADA) - Test input validation: zero/negative amounts, invalid addresses, missing token contract - Test chain support validation with proper error messages - Test successful transfers on multiple chains - Test edge cases: mixed case addresses, 0/18 decimals, different account indices - Test viem integration: client creation, ERC20 encoding, EIP-712 signing - 32 tests covering all critical paths * Fix lint errors in delegation tests * Add EIP-7702 delegation test script Local test script for verifying delegation encoding and signing: - EIP-712 delegation signing - ERC20 transfer encoding - ERC-7579 execution data encoding - Permission context encoding for redeemDelegations Run with: npx ts-node scripts/test-delegation.ts * Add integration tests for EvmTokenStrategy delegation flow - Test pay-in status splitting logic (ACKNOWLEDGED/TO_RETURN vs PREPARING/PREPARED) - Test amount calculation for FORWARD and RETURN types - Test delegation service contract and method calls - Test error handling and legacy fallback scenarios - 13 tests covering the integration between EvmTokenStrategy and Eip7702DelegationService * Add comprehensive smart contract validation tests for EIP-7702 delegation Add 37 new tests to verify correct interaction with DelegationManager contract: - Delegation struct validation (ROOT_AUTHORITY, delegate/delegator mapping, caveats, salt) - Permission context ABI encoding verification - redeemDelegations arguments (CALLTYPE_SINGLE, array structure) - EIP-7702 authorization (DELEGATOR_ADDRESS, deposit account) - ChainId verification for all supported blockchains - Error handling for contract reverts, RPC failures, nonce/gas issues - ERC-7579 execution data format validation * Add Sepolia integration tests for EIP-7702 delegation Add integration tests that verify actual contract interaction on Sepolia: - Contract existence verification (DelegationManager, Delegator) - EIP-712 delegation signature creation and hash computation - ABI encoding verification with round-trip decoding - ERC-7579 execution data format validation - Gas estimation and block limit checks - Full delegation flow dry run Tests are skipped by default unless SEPOLIA_GATEWAY_URL is set. Run with: SEPOLIA_GATEWAY_URL=https://... npm test -- --testPathPattern="integration" * Update tests for dynamic gas estimation in EIP-7702 delegation - Add estimateGas mock to all test describe blocks - Add new Dynamic Gas Estimation test section - Fix mock isolation between test sections - Service now uses publicClient.estimateGas instead of hardcoded 300k gas * Fix DelegationManager ABI to match deployed contract - Change DOMAIN_HASH to getDomainHash (correct function name) - Update integration tests to use getDomainHash - Replace getDelegationHash calls with struct validation * Add live EIP-7702 delegation test script for Sepolia Tested successfully on Sepolia with real USDC transfer: - TX: 0x292dab686f5ba0aa9b22c35ef722289e1458905a6bbb1b4a54a148834c03e44d - Gas used: 127,073 - Transfer: 1 USDC via DelegationManager * Add local development setup with automatic mocking (#2703) * Add local development setup with Docker and automatic mocking Infrastructure: - Add docker-compose.yml with MSSQL Server for local database - Add .env.local.example with minimal config (no secrets) - Add scripts/setup.js for one-command setup Setup Script (npm run setup): - Generate 19 wallet seeds/keys securely on first run - Start API in background (logs to api.log, PID to .api.pid) - Wait for database tables and seed data - Register admin user via API and grant admin role - Seed deposit addresses directly in database Seed Data (migration/seed/): - Add CSV files for language, fiat, country, asset, bank, fee, price_rule - Run seed.js after app start to populate database - Add safety checks to prevent accidental production seeding Mock Mode (ENVIRONMENT=loc): - Mock external HTTP calls (Alchemy, Tatum, Sift, CoinGecko, SumSub) - Mock Azure Storage with in-memory storage - Skip Alchemy webhook creation in local mode - Add sepatools mock for IBAN validation Code Changes: - Extract static chain configs to src/config/chains.config.ts - Clean up .env.example (remove hardcoded URLs/chain IDs) - Add SQL_ENCRYPT=false support for Docker self-signed certs Documentation: - Update README with Local Development section - Document Quick Start, NPM scripts, Docker commands - Explain mock mode and what is/isn't mocked * Fix fiatMap initialization race condition in local development (#2706) - Make PricingService.onModuleInit async and await fiat loading - Run database seeding synchronously before app.listen() in LOC env - Re-initialize PricingService after seeding to load fiat data Previously, onModuleInit used fire-and-forget promises (void) which could complete after the API started accepting requests. Combined with async seeding that ran after app.listen(), this caused "Cannot read properties of undefined (reading 'id')" errors when the fiatMap was empty during price lookups. * Fix: Critical EIP-7702 delegation bugs preventing execution Problem 1: Invalid private key signature error - createSignedDelegation() was using depositViemAccount.source - This is not a valid hex string for signTypedData() Solution: Pass depositPrivateKey: Hex directly Problem 2: Gas parameter conflict - Used legacy gasPrice parameter - Conflicts with EIP-1559 maxFeePerGas/maxPriorityFeePerGas - Error: "Cannot specify both gasPrice and maxFeePerGas" Solution: Use EIP-1559 parameters exclusively Problem 3: Gas estimation failures during testing - Alchemy rate limiting caused estimateGas() to fail Solution: Added try-catch with conservative fallback (150000n) Note: Fallback is for testing resilience - review for production These fixes enable successful EIP-7702 token forwarding in one atomic transaction instead of legacy 2-transaction flow. * Remove gas estimation fallback for EIP-7702 delegation - Remove try-catch with hardcoded 150000n fallback - Let estimateGas() errors propagate to caller - Caller can decide whether to retry or fall back to legacy flow The 150000n fallback was added for testing (Alchemy rate limiting) but is not appropriate for production. Gas estimation failures should be handled at a higher level with proper retry logic. * Fix: Update tests for EIP-1559 gas parameter changes - Add getBlock() and estimateMaxPriorityFeePerGas() mocks to all test blocks - Update error tests to mock estimateGas/getBlock instead of getGasPrice - All 67 tests now passing This fixes test failures introduced by switching from legacy gasPrice to EIP-1559 gas parameters (maxFeePerGas/maxPriorityFeePerGas). * [NO-TASK] Fix: Use pipeline price for all assets, not just FPS/nDEPS (#2670) * [NO-TASK] Fix: Use pipeline price for all assets, not just FPS/nDEPS Previously, the pipeline price (actual exchange rate from liquidity purchase) was only used for FPS and nDEPS assets. For other assets like BTC, the market price was used instead, which could differ from the actual purchase price. This caused price risk during BTC transfers from Binance to HotWallet: - If BTC price drops during transfer, customers expect more BTC than purchased - If BTC price rises during transfer, DFX loses potential margin Changes: - Remove `exchangeRateFromLiquidityOrder` config (was ['FPS', 'nDEPS']) - Remove asset check in `calculateOutputReferenceAmount()` - Link liquidityPipeline to BuyCrypto for ALL assets - Add comprehensive tests (27 test cases) Now all assets benefit from the accurate pipeline price, protecting both customers and DFX from price fluctuations during liquidity transfers. * Fix: Find exchange order from sub-pipelines for BTC purchases The previous implementation used `orders[0].exchangePrice` which doesn't work for BTC purchases because: - Pipeline 41235 (Bitcoin/BTC HotWallet) orders are: NotProcessable, sub-pipeline trigger, withdraw (BTC→BTC) - None have the USDT→BTC exchange rate - The actual exchange rate is in sub-pipeline 41236's order Changes: - Add `exchangeOrder` getter to LiquidityManagementPipeline that finds the order with actual exchange rate (system is exchange, different input/output assets, valid amounts) - Add `subPipelineOrder` getter to find orders that trigger sub-pipelines - Add `getPipelineWithOrders()` to LiquidityManagementService - Add `findExchangeOrder()` to BuyCryptoBatchService that recursively traverses sub-pipelines (max depth 3) to find the exchange order - Modify `calculateOutputReferenceAmount()` to accept exchange order as parameter instead of finding it from `orders[0]` * Fix: Use market price when no trade happened (enough liquidity) When pipeline completes but no exchange order exists (e.g., enough BTC was available at Binance for withdrawal without trading), use market price instead of throwing an error. Scenarios: - Trade happened → use pipeline price (protects against price changes) - No trade needed → use market price (no exchange rate to use) * Fix: Find all exchange orders in pipeline chain The previous implementation only found the first exchange order. Now it recursively traverses all sub-pipelines and collects ALL exchange orders, then aggregates them by asset pair. For Pipeline 41235 (EUR→BTC): - Finds EUR→USDT trades from sub-pipelines 41238/41239 - Finds USDT→BTC trade from sub-pipeline 41236 - Aggregates multiple orders with same asset pair - Replaces CoinGecko steps with actual pipeline prices Example result for Pipeline 41235: Old: CoinGecko EUR→USDT (0.85158), CoinGecko USDT→BTC (86805) New: Kraken EUR→USDT (aggregated), Binance USDT→BTC (86863.47) * Refactor: Move buildAggregatedPriceSteps to HELPER METHODS section * Fix: Include FRANKENCOIN and DEURO in exchange orders filter Without this fix, FPS and nDEPS pipeline prices would not be used because their orders were filtered out by the exchangeOrders getter. * Add tests for FPS/nDEPS and multi-step price matching * [DEV-4473] OCP crypto payout (#2550) * [DEV-4473] Allow crypto routes for OCP * [DEV-4473] Implemented OCP crypto payout pricing * [DEV-4473] Payout aggregation * [DEV-4473] Payout aggregation release * [DEV-4473] PR feedback * [DEV-4473] Merge fixes * Cleanup * [DEV-4473] Fixed price steps * [DEV-4473] Fixed acknowledgement * [NO-TASK] Refactoring * Remove Bank Frick implementation (#2733) * Remove Bank Frick implementation - Remove bank.frick configuration from config.ts - Remove FRICK_* environment variables from .env.example - Remove IbanBankName.FRICK enum from bank.dto.ts - Remove frick parameters from Azure Bicep infrastructure files - Remove frick test mocks and update bank service tests - Keep historical 'Bank Frick' strings in log service for Kraken transaction matching * Fix bank service tests - use olkyEUR instead of maerkiEUR - Tests expected maerkiEUR but service returns first matching bank (olkyEUR) - olkyEUR is first EUR bank in createDefaultBanks() array - Update test expectations to match actual bank selection logic * Remove Kaleido bank implementation (#2737) Kaleido is no longer used in the DFX system. This commit removes: - Kaleido from IbanBankName enum - Kaleido entries from bank.csv seed file (CHF, EUR, USD accounts) Historical data in the database remains intact. * Complete Kaleido removal from codebase (#2738) Removes all remaining Kaleido references: - Removed Blockchain.KALEIDO from blockchain enum - Removed Kaleido from BlockchainExplorerUrls map (blockchain.util.ts) - Removed Kaleido from TxPaths map (blockchain.util.ts) - Removed Kaleido from PayoutLimits map (ref-reward.service.ts) - Removed Kaleido from networks map in 8 exchange services - Removed 3 Kaleido assets from asset.csv seed file (IDs 301-303) Historical database records remain intact. This completes the removal started in PR #2737 which removed IbanBankName.KALEIDO and bank seeds. * feat: Blockchain Balance und Transaction API Endpoints (#2704) * feat: add blockchain balance and transaction API endpoints - Add /blockchain/balances endpoint for querying wallet balances - Add /blockchain/transaction endpoint for creating unsigned transactions - Add /blockchain/broadcast endpoint for broadcasting signed transactions - Support Solana, Tron, and EVM chains (via Alchemy) - New BlockchainBalanceModule with DTOs, services, and controller * fix: use correct base64 encoding for Solana transaction broadcast - Fix broadcastSolanaTransaction to send base64 directly to RPC - Use proper TronWeb import instead of require() - Remove unused TronClient dependency * chore: remove unused TronService from BlockchainTransactionService * fix: align with existing codebase patterns - Use 'x-api-key' header for Tron API (consistent with TronClient) - Use AlchemyNetworkMapper.availableNetworks for EVM blockchain list * Add RateLimitGuard to blockchain endpoints * Add address validation and JSON parse error handling * Fix critical bugs: asset validation and Tron API error handling * Remove IDnow integration (#2739) * Remove IDnow integration - Delete IdentService and remove from module - Remove IDnow config keys (gatewayHost, auto, video) - Disable IDnow webhook and sync endpoints - Block new IDnow ident initiation - Keep historical data parsing (IdentType.ID_NOW, IdNowResult DTOs) Only Sumsub and Manual ident are now supported for new identifications. Historical IDnow ident data remains readable. * Fix: Remove remaining IDnow webhook endpoints and dead code Critical fixes for PR #2739 (Remove IDnow integration): 1. Build Errors Fixed: - Removed Config.kyc.allowedWebhookIps references causing TypeScript errors - All IDnow-related build errors now resolved 2. Endpoints Removed: - identWebhook() - POST /kyc/ident/:type - identRedirect() - GET /kyc/ident/:type/:channel/:status - checkWebhookIp() helper method 3. Functions Removed: - updateIdentStatus() from KycService (only called by removed endpoint) - syncIdentStep() from KycAdminService (dead code, always throws) 4. Imports Cleaned: - Removed unused IdNowResult and IdentStatus imports Impact: - IDnow webhooks and redirects no longer accepted - Build now succeeds (remaining 9 errors are unrelated Bitcoin client issues) - No runtime errors for IDnow webhook calls - Old IDnow ident data remains fully readable Related to: #2739 * Fix TypeScript errors in bitcoin client (#2740) Fixes all 9 TypeScript compilation errors in bitcoin-client.ts and node-client.ts: ## Module Declaration Errors (2 fixed) - Added @ts-ignore comments for @btc-vision/bitcoin-rpc imports - Package has no type declarations, suppression is necessary ## Type Inference Errors (7 fixed) - Added explicit type parameters to callNode<T>() calls - Defined SendResult and WalletInfo interfaces for RPC responses - Fixed bitcoin-client.ts: - send() → callNode<{ txid: string }>() - sendMany() → callNode<{ txid: string }>() - sendSignedTransaction() → callNode<string>() - Fixed node-client.ts: - getBlockCount() → callNode<number>() - getBlockHash() → callNode<string>() - getBalance() → callNode<WalletInfo>() - sendUtxoToMany() → callNode<SendResult>() All changes are type-only annotations - no functional changes. TypeScript compilation now passes with zero errors. * Fix local development password to avoid shell special characters (#2742) Changed SQL_PASSWORD from LocalDev123! to LocalDev2026@SQL to prevent issues with special characters (!) in shell environments. The exclamation mark can cause problems with Bash history expansion and command execution. Updated in: - docker-compose.yml (MSSQL_SA_PASSWORD, healthcheck, db-init) - scripts/setup.js (database config defaults) - migration/seed/seed.js (database config default) - .env.local.example (SQL_PASSWORD) * chore: reformat code with Prettier v3 (#2743) * fix: enable ESLint rules and fix violations (#2744) * Remove Revolut bank integration (#2745) * Remove Revolut bank integration - Delete revolut.service.ts - Remove RevolutService from bank module - Remove REVOLUT enum from IbanBankName - Remove REVOLUT_CARD_PAYMENT transaction type - Remove Revolut transaction sync from bank-tx service - Remove Revolut balance monitoring from bank observer - Remove Revolut config - Remove Revolut seed data * Remove Revolut environment variables from infrastructure * fix: wrap case blocks with lexical declarations in braces (#2746) * fix(eslint): fix remaining ESLint rule violations (#2748) * fix(eslint): fix no-async-promise-executor violations - Refactor Util.poll() to use async/await directly without Promise wrapper - Pre-generate QR codes in generateClassicStickersPdf before Promise - Remove async from generateBitcoinFocusStickersPdf executor (no await inside) - Re-enable no-async-promise-executor rule * fix(eslint): fix no-unused-expressions violations (58 fixes) Convert short-circuit expressions to proper if statements: - `condition && action()` → `if (condition) action();` - `value && (obj.prop = value)` → `if (value) obj.prop = value;` Re-enable @typescript-eslint/no-unused-expressions rule * fix(eslint): fix simple warnings (#2749) - Remove 5 unused eslint-disable directives - Remove 9 unused catch error variables (use empty catch) - Remove 3 unused imports in kyc files - Prefix 2 unused function params with underscore * fix(eslint): fix all remaining console warnings (#2752) - Add ESLint override to disable no-console for test files (*.spec.ts, *.test.ts, __tests__) - Add DfxLogger to EvmClient and replace console.log with logger.verbose - Change logger from private to protected in EvmClient and subclasses for proper inheritance * Fix remaining ESLint warnings for scripts folder (#2753) - Add scripts/**/*.ts to no-console override (73 warnings) - Add migration/**/*.js and scripts/*.js to ignores (3 parsing errors) - Fix unused walletClient variable with underscore prefix - Fix unused error in catch block with empty catch * Remove deprecated interface-name-prefix ESLint rule (#2754) * [NOTASK] Small refactoring * feat: add feature flag for pipeline price mechanism (#2756) Add USE_PIPELINE_PRICE_FOR_ALL_ASSETS environment variable to control whether the pipeline price (actual exchange rate from liquidity purchase) is used for all assets. When disabled (default): Market price is used for all assets When enabled: Pipeline price is used when available This allows gradual rollout of the pipeline price feature introduced in commit 7b0b6e6. Changes: - Add usePipelinePriceForAllAssets config option - Guard pipeline price logic with feature flag in buy-crypto.entity.ts - Guard exchange order lookup with feature flag in buy-crypto-batch.service.ts * [NO-TASK] Payment step timestamp fix * [NO-TASK] Cleanup * fix: enable pipeline price feature flag in tests (#2757) The pipeline price tests require the usePipelinePriceForAllAssets config option to be enabled. Add beforeEach block to configure the feature flag for the liquidityPipeline test suite. * [DEV-4516] change financeLog to yapeal (#2700) * [DEV-4516] change financeLog to yapeal * [DEV-4516] Refactoring * [DEV-4516] Refactoring 2 * [NO-TASK] Cleanup 2 * refactor(bitcoin): replace @btc-vision/bitcoin-rpc with custom RPC client (#2758) * fix(bitcoin): use positional parameters for RPC calls Switch from named parameters (objects) to positional parameters (arrays) for all Bitcoin Core RPC calls to ensure compatibility with servers that don't fully support named parameters. Changes: - Add callRpcWithPositionalParams helper method for direct HTTP RPC calls - Update all RPC methods to use positional parameters - Remove unused getInternalRpcClient method - Add WalletInfo interface locally This fixes "Params must be an array or object" errors that occurred when the Bitcoin Core server doesn't support named parameter format. * refactor(bitcoin): replace @btc-vision/bitcoin-rpc with custom RPC client Removes the @btc-vision/bitcoin-rpc dependency and replaces it with our own minimal, fully-typed Bitcoin Core RPC client that uses positional parameters. New files in src/integration/blockchain/bitcoin/node/rpc/: - bitcoin-rpc-client.ts: Minimal RPC client (~230 lines) - bitcoin-rpc-types.ts: Full TypeScript type definitions (~190 lines) - index.ts: Barrel exports Key improvements: - Uses positional parameters (arrays) for maximum Bitcoin Core compatibility - Full TypeScript type definitions for all RPC methods - Only implements the ~15 methods needed by DFX - No external dependencies beyond existing HTTP service - Cleaner, more maintainable code in node-client.ts and bitcoin-client.ts This fixes the "Params must be an array or object" error caused by @btc-vision/bitcoin-rpc using named parameters (objects) which some Bitcoin Core servers don't support. * refactor(bitcoin): replace @btc-vision/bitcoin-rpc with custom RPC client Removes the @btc-vision/bitcoin-rpc dependency and replaces it with our own minimal, fully-typed Bitcoin Core RPC client that uses positional parameters. New files in src/integration/blockchain/bitcoin/node/rpc/: - bitcoin-rpc-client.ts: Minimal RPC client (~230 lines) - bitcoin-rpc-types.ts: Full TypeScript type definitions (~190 lines) - index.ts: Barrel exports Key improvements: - Uses positional parameters (arrays) for maximum Bitcoin Core compatibility - Full TypeScript type definitions for all RPC methods - Only implements the ~15 methods needed by DFX - No external dependencies beyond existing HTTP service - Cleaner, more maintainable code in node-client.ts and bitcoin-client.ts - Preserves full URL including protocol (http/https) and path (/wallet/...) This fixes the 'Params must be an array or object' error caused by @btc-vision/bitcoin-rpc using named parameters (objects) which some Bitcoin Core servers don't support. * [NO-TASK] Renaming * [DEV-4473] Network fee fix * test(bitcoin): add comprehensive tests for custom RPC client (#2759) * fix(bitcoin): use positional parameters for RPC calls Switch from named parameters (objects) to positional parameters (arrays) for all Bitcoin Core RPC calls to ensure compatibility with servers that don't fully support named parameters. Changes: - Add callRpcWithPositionalParams helper method for direct HTTP RPC calls - Update all RPC methods to use positional parameters - Remove unused getInternalRpcClient method - Add WalletInfo interface locally This fixes "Params must be an array or object" errors that occurred when the Bitcoin Core server doesn't support named parameter format. * refactor(bitcoin): replace @btc-vision/bitcoin-rpc with custom RPC client Removes the @btc-vision/bitcoin-rpc dependency and replaces it with our own minimal, fully-typed Bitcoin Core RPC client that uses positional parameters. New files in src/integration/blockchain/bitcoin/node/rpc/: - bitcoin-rpc-client.ts: Minimal RPC client (~230 lines) - bitcoin-rpc-types.ts: Full TypeScript type definitions (~190 lines) - index.ts: Barrel exports Key improvements: - Uses positional parameters (arrays) for maximum Bitcoin Core compatibility - Full TypeScript type definitions for all RPC methods - Only implements the ~15 methods needed by DFX - No external dependencies beyond existing HTTP service - Cleaner, more maintainable code in node-client.ts and bitcoin-client.ts This fixes the "Params must be an array or object" error caused by @btc-vision/bitcoin-rpc using named parameters (objects) which some Bitcoin Core servers don't support. * refactor(bitcoin): replace @btc-vision/bitcoin-rpc with custom RPC client Removes the @btc-vision/bitcoin-rpc dependency and replaces it with our own minimal, fully-typed Bitcoin Core RPC client that uses positional parameters. New files in src/integration/blockchain/bitcoin/node/rpc/: - bitcoin-rpc-client.ts: Minimal RPC client (~230 lines) - bitcoin-rpc-types.ts: Full TypeScript type definitions (~190 lines) - index.ts: Barrel exports Key improvements: - Uses positional parameters (arrays) for maximum Bitcoin Core compatibility - Full TypeScript type definitions for all RPC methods - Only implements the ~15 methods needed by DFX - No external dependencies beyond existing HTTP service - Cleaner, more maintainable code in node-client.ts and bitcoin-client.ts - Preserves full URL including protocol (http/https) and path (/wallet/...) This fixes the 'Params must be an array or object' error caused by @btc-vision/bitcoin-rpc using named parameters (objects) which some Bitcoin Core servers don't support. * test(bitcoin): add comprehensive tests for custom RPC client Add unit tests and integration tests for the new Bitcoin RPC implementation: - bitcoin-rpc-client.spec.ts: 46 tests for RPC parameter ordering, auth, error handling - node-client.spec.ts: 39 tests for URL handling, fee conversion, retry logic - bitcoin-client.spec.ts: 46 tests for send, sendMany, testMempoolAccept - bitcoin-fee.service.spec.ts: 23 tests for caching and status handling - bitcoin-rpc.integration.spec.ts: Extended with fee estimation, mempool, CLI tests Total: 235 tests covering all critical paths of the Bitcoin RPC migration. * fix(test): remove unused imports and variables - Remove unused imports: AddressType, InWalletTransaction, Block - Remove unused imports: TxFeeRateResult, TxFeeRateStatus - Prefix unused parameter with underscore: _address - Remove unused variable assignment: result * feat(bitcoin): add getRawTransaction and RPC client improvements (#2761) - Add getRawTransaction method to BitcoinRpcClient with verbosity support - Add RawTransaction type with comprehensive transaction data fields - Add tests for getRawTransaction including edge cases - Improve error handling for transaction not found (-5) errors - Add additional integration test coverage for RPC client * fix(buy-crypto): reset batch when setting missing liquidity status (#2762) When a BuyCrypto transaction is set to MISSING_LIQUIDITY status, the batch reference was not being cleared. This caused transactions to become stuck because the batch query requires batch to be null for transactions to be re-processed. This fix ensures that when liquidity is missing, the transaction is properly detached from its batch so it can be picked up again when liquidity becomes available. * [NO-TASK] Changed path * fix: translate German comments to English in Bitcoin RPC tests (#2760) Translate JSDoc header comments from German to English for consistency. * fix: remove unused mock services (#2763) Remove orphaned mock services from /integration/mock/ that were never imported or used. The MockModule.forRoot() was never called anywhere in the application. Actual mocking is done inline in real services (HttpService, AzureStorageService, etc.) via Environment.LOC checks. Removed files: - mock.module.ts - mock-http.service.ts - mock-storage.service.ts - mock-mail.service.ts - mock-alchemy.service.ts - index.ts * revert: remove batch reset in setMissingLiquidityStatus (#2764) Reverts the change from PR #2762 that added `batch: null` when setting MISSING_LIQUIDITY status. * [NO-TASK] BTC balance fix * fix(tests): update getBalance tests to use getbalances RPC Update test mocks to use getbalances RPC method with correct response structure { mine: { trusted: ... } } instead of deprecated getwalletinfo. * fix(lint): remove empty else block in evm.strategy.ts --------- Co-authored-by: bernd2022 <bernd.nospam.2018@t-online.de> Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Co-authored-by: TuanLamNguyen <xnguyen.lam@gmail.com> Co-authored-by: David May <david.leo.may@gmail.com> Co-authored-by: David May <85513542+davidleomay@users.noreply.github.com>
* fix(bitcoin): enable 0-conf by default (#2765) Remove ALLOW_UNCONFIRMED_UTXOS env variable dependency and always enable unconfirmed UTXO support for BTC transactions. * fix(bitcoin): improve RPC error handling Extract and display actual RPC error messages from Bitcoin Core instead of generic HTTP status codes. * fix(bitcoin): preserve error code and SyntaxError in RPC client - Preserve SyntaxError for retry logic in NodeClient - Preserve error code property when re-throwing errors - Update tests to use toContain() for error message assertions
[NO-TASK] Fixed BTC payout aggregation
…2769) * Fix Bitcoin liquidity check to include unconfirmed UTXOs - Modified getBalance() to return confirmed + unconfirmed balance (trusted + untrusted_pending) - Added include_unsafe option to sendMany() to allow spending unconfirmed UTXOs - Extended TypeScript interface with all Bitcoin Core send() options - Updated unit tests to verify new behavior This fixes the issue where BuyCrypto transactions remain in 'MissingLiquidity' status even when sufficient unconfirmed UTXOs are available in the wallet. * Use Config.blockchain.default.allowUnconfirmedUtxos flag - Make getBalance() respect allowUnconfirmedUtxos config (currently hardcoded to true) - Make sendMany() include_unsafe conditional on allowUnconfirmedUtxos config - Update tests to mock allowUnconfirmedUtxos config value - Improve comment accuracy: 'trusted' includes wallet's own unconfirmed UTXOs
* feat(realunit): adjust KYC level requirements based on amount (#2771) - KYC Level 20 is now sufficient for amounts up to 1000 CHF - KYC Level 50 is still required for amounts above 1000 CHF - EUR amounts are converted to CHF for the limit check - Uses existing Config.tradingLimits.monthlyDefaultWoKyc threshold * feat(realunit): adjust KYC requirements and set Level 20 on registration (#2772) - KYC Level 20 is now sufficient for amounts up to 1000 CHF - KYC Level 50 is still required for amounts above 1000 CHF - EUR amounts are converted to CHF for the limit check - RealUnit registration now sets KYC Level 20 when completed - Added @ispositive validator to prevent zero/negative amounts * Fix mail login redirect to use /account instead of /kyc (#2773) After signing in via email link, users are now redirected to /account instead of /kyc, which provides a better default landing page for authenticated users without specific KYC context. * Add bank holidays for 2026 (#2780) * Add vIBAN search to compliance endpoint (#2775) * Add vIBAN search to compliance endpoint - Add VIBAN to ComplianceSearchType enum - Extend support service to search in VirtualIban table - Add search in BankTx.virtualIban column - Include unassigned BankTx for vIBAN results * [NOTASK] Refactoring --------- Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> * Fix email UX: display button before fallback link (#2774) Currently, emails display the URL link first, followed by the button. This creates a poor user experience as most users can see buttons, making the link redundant for the majority. Changes: - Reorder email content to show button first, then link - Update all translations (de/en/pt) to reflect new order - Add "or" prefix to link text to indicate it's a fallback option Affected emails: - Login email (auth.service.ts) - KYC reminder, failed, and missing data emails (kyc-notification.service.ts) - Account merge request email (account-merge.service.ts) This improves UX by prioritizing the primary action (button) and making the plain-text link available only for clients that don't support buttons. * Add Liechtenstein bank holidays 2026 and prevent fiat output on holidays (#2779) * Add Liechtenstein bank holidays 2026 and prevent fiat output on holidays - Add liechtenstein-bank-holiday.config.ts with 2026 holidays - Update fiat-output-job.service to check for LI/CH bank holidays - Block isReadyDate on bank holidays and day before after 16:00 * Restrict bank holiday check to LI IBANs only - Bank holiday blocking now only applies to Liechtenstein IBANs - CH and other IBANs are not affected by holiday checks - Remove unused isBankHoliday import * Restrict bank holiday check to LiqManagement type only - Bank holiday blocking now only applies to FiatOutputs with type LiqManagement - Other types (BuyFiat, BuyCryptoFail, etc.) are not affected * Improve bank holiday check implementation - Add verbose logging when FiatOutput is blocked due to bank holiday - Use early return (continue) for better readability - Only calculate isAfter16 when actually needed (performance) - Clearer variable scoping and logic flow * Address PR review comments - Remove unused getLiechtensteinBankHolidayInfoBanner function and import - Simplify holiday check: combine conditions with || operator - Remove unnecessary intermediate variables (isLiIban, isLiqManagement, etc.) - Use single logger.verbose message for bank holiday blocking * [NOTASK] Refactoring --------- Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> * Add Sepolia USDT token asset (#2783) * Add Sepolia USDT to asset seed file (#2784) * Fix sell deposit tx creation with missing user address and deposit relation (#2785) Two bugs were causing 'Failed to create deposit transaction: invalid address or ENS name': 1. In toPaymentInfoDto(): The transactionRequest only contained user: { id: userId } without the address field. Fixed by explicitly passing user.address. 2. In depositTx controller endpoint: getById() did not load the deposit relation, so route.deposit was undefined. Fixed by adding relations: { deposit: true }. Also added validation to throw clear errors if address or deposit is missing. * chore(ci): add npm caching and improve build tooling (#2788) - Add npm cache to GitHub Actions workflows (api-pr, api-dev, api-prd) for faster CI builds - Add new npm scripts: - type-check: Run tsc --noEmit for type validation without build - format:check: Check formatting without modifying files - Add forceConsistentCasingInFileNames to tsconfig.json - Upgrade @typescript-eslint/no-floating-promises from warn to error * feat: add EIP-7702 delegation support for gasless Sell and Swap Enable users to sell and swap tokens without holding ETH for gas. The backend relayer covers gas costs through MetaMask's delegation contract. Changes: - Add EIP7702DelegationService for gasless transaction preparation - Add EIP-7702 delegation DTOs for frontend communication - Add DELEGATION_TRANSFER PayInType enum value - Update Sell/Swap services to detect zero-balance users - Add depositTx endpoint to Swap controller (parity with Sell) - Add ?includeTx parameter to Swap for optional TX data - Improve gas estimation with fallback for EIP-7702 delegated addresses - Use StaticJsonRpcProvider for better performance Contracts: - MetaMask Delegator: 0x63c0c19a282a1b52b07dd5a65b58948a07dae32b - DelegationManager: 0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3 * Skip Bitcoin pay-in processing when node is unavailable (#2789) Add isAvailable() check to PayInBitcoinService to prevent errors when Bitcoin node is not configured (e.g., local development). The BitcoinStrategy cron job and unconfirmed UTXO processing now gracefully skip when the service is unavailable. * Skip bank transaction check when Olky bank is not configured (#2790) Return early from checkTransactions() if no Olky bank is found in the database, preventing null pointer errors in local development. * Skip blockchain services when config is unavailable (#2791) - FrankencoinService: Skip processLogInfo when xchf contract not configured - DEuroService: Skip processLogInfo when graphUrl not configured - PaymentLinkFeeService: Skip updateFees in local environment Prevents errors in local development when external services are not configured. * Add warning logs for missing config (#2793) Log a warning when config is missing instead of silently skipping or throwing errors. Simple and consistent approach. Affected services: - BitcoinStrategy: warns if Bitcoin node not configured - PayInService: warns if Bitcoin service unavailable - BankTxService: warns if Olky bank not found - FrankencoinService: warns if xchf contract not configured - DEuroService: warns if graphUrl not configured * feat: different exceptions for buy endpoint (#2794) * feat: create different exceptions for buy endpoint. * chore: status codes. * chore: comments. * Log missing config warnings only once (#2795) * Log missing config warnings only once Prevent log spam by tracking if warning was already logged. Affects high-frequency cron jobs: - BitcoinStrategy (every second) - BankTxService (every 30 seconds) * Skip services gracefully when dependencies are unavailable - Add isAvailable() check to CheckoutService - Add availability check to CheckoutObserver with warning-once pattern - Add availability check to FiatPayInSyncService with warning-once pattern - Change ExchangeTxService to warn-once on sync failures - Add null check for client in TransactionHelper.getNetworkStartFee - Add null check for client in LogJobService.getAssetLog - Fix PaymentObserver to use optional chaining for outputDate * Add missing null checks for graceful degradation - Add null checks for client and targetAddress in PaymentBalanceService - Also check for coin existence before setting balance - Extend CheckoutService.isAvailable() to also check Config.checkout.entityId * Make warning-once pattern consistent across all services - Add warning-once with Set<Blockchain> to PaymentBalanceService - Add warning-once with Set<Blockchain> to LogJobService - Add warning-once with Set<Blockchain> to TransactionHelper All services now consistently log warnings only once when blockchain clients are not configured. * Add readonly to syncWarningsLogged Set for consistency * Add missing blank line after early return for consistency * fix(swap): correct misleading includeTx default value (#2792) * fix(swap): correct misleading includeTx default value The controller always passes an explicit boolean via `includeTx === 'true'`, so the service default was never used. Change from `true` to `false` to accurately reflect the actual behavior (depositTx is only included when explicitly requested via ?includeTx=true). * fix(custody): pass explicit includeTx=false to swap service Make custody order swap calls explicit about not including depositTx, matching the pattern used for sell orders. This ensures the default value change in swap.service.ts has no functional impact. Affected calls: - CustodyOrderType.SWAP - CustodyOrderType.SEND - CustodyOrderType.RECEIVE * Fix flaky timing test in lock.spec.ts (#2796) Replace timing-based test with Promise-based synchronization. The original test used setTimeout without delay causing race conditions. The new test uses explicit Promise signaling for deterministic behavior. * feat(gs): add debug endpoint for secure database queries (#2770) * feat(gs): add debug endpoint for secure database queries Add new DEBUG user role for developer database access with POST /gs/debug endpoint for executing read-only SQL queries. Security layers: - Role-based access (DEBUG/ADMIN/SUPER_ADMIN only) - SQL parsing with node-sql-parser (AST validation) - Only single SELECT statements allowed - Blocked: UNION/INTERSECT/EXCEPT, SELECT INTO, FOR XML/JSON - Blocked: OPENROWSET, OPENQUERY, OPENDATASOURCE (external connections) - Pre-execution column checking (blocks alias bypass) - Input validation with MaxLength(10000) - Post-execution PII column masking (defense in depth) - Full audit trail with user identification Blocked columns: mail, email, firstname, surname, iban, ip, apiKey, etc. * fix(gs): resolve eslint warnings in debug endpoint - Remove unused catch variable (use bare catch) - Remove unnecessary eslint-disable directive * [NOTASK] add more blockedCols * fix(gs): move restricted columns from ADMIN to DEBUG blocking - Remove organization.name, bank_tx.name, kyc_step.result from RestrictedColumns - Add 'name' and 'result' to DebugBlockedColumns - ADMIN can now see these columns on /gs/db - DEBUG role has these blocked on /gs/debug * fix(gs): implement table-specific column blocking for debug endpoint (#2782) * fix(gs): implement table-specific column blocking for debug endpoint Replace generic DebugBlockedColumns list with table-specific blocking: - TableBlockedColumns: Record<string, string[]> maps each table to its blocked columns - Pre-execution: Check columns against their specific tables - Post-execution for SELECT *: Mask columns from all query tables Examples: - SELECT name FROM asset → ALLOWED (asset has no blocked columns) - SELECT name FROM bank_tx → BLOCKED (bank_tx.name contains personal data) - SELECT * FROM bank_tx → name masked post-execution Tables with blocked columns: - user_data: mail, phone, firstname, surname, etc. - bank_tx: name, iban, addressLine1, etc. - bank_data: name, iban, label, comment - kyc_step: result (contains names, birthday) - organization: name, allBeneficialOwnersName, etc. * fix(gs): always run post-execution masking for defense in depth The previous implementation only masked post-execution for SELECT * queries. This was a security risk: if pre-execution column extraction failed (catch block), non-wildcard queries would not be masked. Now post-execution masking always runs, ensuring blocked columns are masked even if the SQL parser fails to detect them pre-execution. * fix(gs): add missing blocked columns from original list Add columns that were in the original DebugBlockedColumns but missing in the new table-specific structure: - user_data: countryId, verifiedCountryId, nationalityId - user: signature - fiat_output: accountNumber - checkout_tx: cardName (new table) - bank_account: accountNumber (new table) * fix(gs): add missing tables with sensitive columns Add tables that were missed when converting from global DebugBlockedColumns to table-specific TableBlockedColumns: - ref: ip (user IP for referral tracking) - ip_log: ip, country (user IP logging) - checkout_tx: ip (user IP during checkout, cardName already present) - buy: iban (user IBAN for buy routes) - deposit_route: iban (user IBAN for sell routes via Single Table Inheritance) These columns were blocked globally in the original implementation but were not added to all relevant tables in the table-specific version. * fix(gs): add additional sensitive columns found in codebase review Add missing blocked columns discovered during comprehensive entity scan: - buy_crypto: chargebackIban (user IBAN for refunds) - kyc_log: ipAddress (TfaLog), result (KYC data) - bank_tx_return: chargebackIban, recipientMail, chargebackRemittanceInfo - bank_tx_repeat: chargebackIban, chargebackRemittanceInfo - limit_request: recipientMail - ref_reward: recipientMail * fix(gs): add additional sensitive columns from codebase review Extend existing tables with missing blocked columns: - checkout_tx: cardBin, cardLast4, cardFingerPrint, cardIssuer, cardIssuerCountry, raw - buy_crypto: chargebackRemittanceInfo, siftResponse - buy_fiat: remittanceInfo, usedBank, info - crypto_input: senderAddresses - user_data: relatedUsers - limit_request: fundOriginText - bank_tx_return: info Add new tables with sensitive columns: - transaction_risk_assessment: reason, methods, summary, result (AML/KYC assessments) - support_issue: name, information (support tickets with user data) - support_message: message, fileUrl (message content and files) - sift_error_log: requestPayload (Sift API requests with PII) * fix(gs): add webhook.data to blocked columns * fix(gs): add notification.data to blocked columns * fix(gs): add kyc_step.data to blocked columns * feat(gs): add App Insights log query endpoint with template-based security (#2778) Add POST /gs/debug/logs endpoint for querying Azure Application Insights logs using predefined, safe KQL templates. Security features: - Template-based queries only (no free-form KQL input) - Strict parameter validation via class-validator (GUID, alphanumeric) - All KQL-relevant special characters blocked in user input - Defense-in-depth string escaping - Result limits per template (200-500 rows) - Full audit logging of queries Available templates: - traces-by-operation: Traces for specific operation ID - traces-by-message: Traces filtered by message pattern - exceptions-recent: Recent exceptions - request-failures: Failed HTTP requests - dependencies-slow: Slow external dependencies (by duration threshold) - custom-events: Custom events by name Infrastructure: - AppInsightsQueryService: OAuth2 client with token caching - Proper error handling and logging - Mock responses for LOC mode Requires UserRole.DEBUG and APPINSIGHTS_APP_ID env variable. * fix(gs): add security hardening for debug SQL endpoint Security improvements: 1. Block system tables and schemas: - Added BlockedSchemas list: sys, information_schema, master, msdb, tempdb - checkForBlockedSchemas() validates FROM clause and subqueries - Prevents access to sys.sql_logins, INFORMATION_SCHEMA.TABLES, etc. 2. Fix TOP validation to use AST instead of regex: - Previous regex /\btop\s+(\d+)/ missed TOP(n) with parentheses - Now uses stmt.top?.value from AST for accurate detection - Both TOP 100 and TOP(100) are correctly validated 3. Extend dangerous function check to all clauses: - Previous check only validated FROM clause - Now recursively checks SELECT columns and WHERE clauses - checkForDangerousFunctionsRecursive() traverses entire AST - Blocks OPENROWSET, OPENQUERY, OPENDATASOURCE, OPENXML everywhere * refactor(gs): improve code professionalism in debug endpoints - Remove commented debug code - Fix return type any[] → Record<string, unknown>[] - Remove redundant try-catch in controller (service handles errors) - Rename misleading parameter userMail → userIdentifier - Standardize comment style * fix(gs): restore table-specific column blocking for debug endpoint (#2797) PR #2778 accidentally reverted PR #2782's TableBlockedColumns changes due to a git reset that preserved stale local file contents. This commit restores: - TableBlockedColumns: Record<string, string[]> with 30+ table-specific blocked column lists (42 columns across 23 tables) - getTablesFromQuery(): Extract table names from SQL AST - getAliasToTableMap(): Map table aliases to real names - isColumnBlockedInTable(): Table-aware column blocking check - findBlockedColumnInQuery(): Pre-execution validation with table context - maskDebugBlockedColumns(): Post-execution masking with table context Security impact of the regression: - Columns like comment, label, data, message, fileUrl, remittanceInfo, txRaw, chargebackIban, siftResponse, requestPayload were unblocked - Table-specific blocking allows SELECT name FROM asset (harmless) while blocking SELECT name FROM bank_tx (PII) All new features from later commits are preserved: - BlockedSchemas, DangerousFunctions - checkForBlockedSchemas(), checkForDangerousFunctionsRecursive() - LogQueryTemplates, executeLogQuery(), AppInsightsQueryService --------- Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> * feat(realunit): add dev payment simulation for REALU purchases (#2798) * feat(realunit): add dev payment simulation for REALU purchases Add automatic payment simulation for REALU TransactionRequests in DEV/LOC environments. When a user creates a REALU payment info, the system now automatically simulates the bank payment and creates a BuyCrypto entry. Changes: - Add RealUnitDevService with cron job (every minute) - Query TransactionRequests for Mainnet REALU (how they're created) - Create BuyCrypto with Sepolia REALU asset (for testnet payout) - Set amlCheck: PASS to bypass AML processing - Add Sepolia REALU asset (ID 408) to seed and migration - Export BuyCryptoRepository from BuyCryptoModule - Export TransactionRequestRepository from PaymentModule - Fix toWeiAmount for tokens with 0 decimals Flow: PaymentInfo (Mainnet REALU) -> Simulation -> BuyCrypto (Sepolia) -> Cron jobs process -> Payout via SepoliaTokenStrategy * fix(realunit): allow multiple TransactionRequests per Buy route Change duplicate check from bankUsage to txInfo-based. Previously, only the first TransactionRequest for a Buy route would be simulated because subsequent requests found the existing BankTx by bankUsage. Now each TransactionRequest is tracked by its unique simulation marker in the txInfo field, allowing multiple payments to the same route. * test(evm): add unit tests for toWeiAmount with decimals=0 Add comprehensive tests for EvmUtil.toWeiAmount and fromWeiAmount: - decimals=0 (REALU case) - critical for tokens without fractional units - decimals=undefined (native coin) - defaults to 18 decimals - decimals=6 (USDT/USDC) - common stablecoin format - decimals=18 (standard ERC20) - fractional amounts with decimals=0 (rounds to nearest integer) - large amounts with decimals=0 These tests verify the fix for the decimals=0 bug where `decimals ? x : y` incorrectly treated 0 as falsy. * ci: add automatic release PR workflow (#2800) Creates a PR from develop to master automatically when: - Changes are pushed to develop - No open release PR exists Features: - Concurrency control to prevent race conditions - Explicit master branch fetch for reliable diff - Manual trigger support via workflow_dispatch - Commit count in PR description * ci: add type-check, format-check and security audit to pipelines (#2803) - Add npm run type-check step to verify TypeScript compilation - Add npm run format:check step to enforce Prettier formatting - Add npm audit --audit-level=high as non-blocking warning - Fix formatting in source files to pass format:check - Add CLAUDE.md to gitignore Applied to all workflows: api-pr.yaml, api-dev.yaml, api-prd.yaml * fix(gs): harden FOR XML/JSON check and add security tests (#2799) * fix(gs): harden FOR XML/JSON check and add security tests - Replace string-based FOR XML/JSON check with regex after normalizing comments and whitespace to prevent bypass via FOR/**/XML or FOR\tXML - Add comprehensive security test suite covering: - FOR XML/JSON bypass attempts (comment, tab, newline, multi-space) - Statement type validation (INSERT, UPDATE, DELETE, DROP) - PII column blocking (direct, aliased, subquery) - System schema blocking (sys, INFORMATION_SCHEMA, master) - Dangerous function blocking (OPENROWSET, OPENQUERY, OPENDATASOURCE) - UNION/INTERSECT/EXCEPT blocking - SELECT INTO blocking * fix(gs): use AST-based FOR XML/JSON detection instead of regex The regex approach had vulnerabilities: - Inline comment bypass: FOR -- x\nXML AUTO was not blocked - False positives: 'FOR XML' in string literals was incorrectly blocked AST-based detection using stmt.for.type is more robust: - Correctly blocks all FOR XML/JSON variants including inline comment bypass - No false positives for string literals - Consistent with the rest of the AST-based security checks Added tests: - Inline comment bypass attempt (now blocked) - String literal false positive test (now allowed) * fix(gs): check FOR XML/JSON recursively in subqueries Critical fix: The previous AST-based check only looked at stmt.for on the top-level statement. Subqueries in SELECT columns, FROM clause (derived tables), WHERE clause, and CTEs were not checked, allowing bypass via: - SELECT id, (SELECT mail FROM user_data FOR XML PATH) FROM [user] - SELECT * FROM (SELECT * FROM user_data FOR XML AUTO) as t Added recursive checkForXmlJsonRecursive() that traverses the entire AST to find FOR XML/JSON in any subquery. Tests added: - FOR XML in subquery (SELECT column) - FOR XML in derived table (FROM clause) * fix(gs): cover all FOR XML/JSON bypass vectors Extended checkForXmlJsonRecursive to cover: - HAVING clause subqueries - ORDER BY clause subqueries - JOIN ON condition subqueries - CASE expression branches (result/condition fields) Extended checkNodeForXmlJson to handle: - node.result for CASE THEN branches - node.condition for CASE WHEN conditions - node.value arrays for IN clauses Changed columns check to use checkNodeForXmlJson instead of just checking col.expr?.ast, ensuring CASE expressions and other complex column expressions are fully traversed. Added 4 new tests for the previously uncovered bypass vectors. * Add GROUP BY and WINDOW OVER FOR XML/JSON checks - Add check for subqueries in GROUP BY clause - Add check for subqueries in WINDOW OVER (ORDER BY, PARTITION BY) - Add 4 new tests covering these bypass vectors * Fix schema and dangerous function bypass vectors - checkForBlockedSchemas: Add checks for SELECT columns, HAVING, ORDER BY, GROUP BY, CTEs, JOIN ON, and WINDOW OVER clauses - checkForDangerousFunctionsRecursive: Add checks for HAVING, ORDER BY, GROUP BY, CTEs, JOIN ON, and WINDOW OVER clauses - Add CASE expression and array value checks to both functions - Add 10 new tests covering all bypass vectors * Block linked server access (4-part names) - Add check for item.server property in checkForBlockedSchemas - Block all linked server access to prevent external database access - Add 2 tests for linked server blocking * Fix formatting * perf: parallelize async operations in swap quote API (#2805) - Parallelize getSourceSpecs/getTargetSpecs calls in transaction-helper - Parallelize blockchain fee calculations in fee.service These independent operations were running sequentially, causing unnecessary latency in the swap quote endpoint. * fix(security): resolve all CodeQL security findings (#2806) * fix(security): resolve all CodeQL security findings - Path injection (ocp-sticker.service.ts): Validate lang against allowed values - Type confusion (spark.service.ts): Add nullish coalescing for Map.get() - Missing permissions (api-*.yaml): Add explicit 'contents: read' permissions - Polynomial ReDoS (gs.service.ts): Replace regex with simple string search - Incomplete sanitization (olkypay.service.ts): Use replaceAll instead of replace Resolves 9 CodeQL alerts * fix(gs): use bounded quantifier for ORDER BY detection Replace .includes('order by') with bounded regex /order\s{1,100}by/i: - Prevents ReDoS via bounded quantifier {1,100} - Maintains support for tabs and multiple spaces between ORDER and BY - Original .includes() only matched single space * feat(cron): add logging for skipped cron jobs (#2807) * Fix race condition in ProcessService initialization This reverts the regression introduced in commit 0727fed which caused all processes to be treated as "disabled" during the initial startup window before async resyncDisabledProcesses() completed. Changes: - Initialize DisabledProcesses with empty map {} instead of undefined - Simplify DisabledProcess() to only return true when explicitly disabled - Add synchronous initialization from Config.disabledProcesses() - Add logging to DfxCronService when jobs are skipped due to disabled process The previous logic returned true (disabled) when DisabledProcesses was undefined, causing a race condition where cron jobs triggered before the async initialization completed would be silently skipped. * style: fix prettier formatting * refactor: keep only logging, revert race condition fix Keep the useful logging for skipped cron jobs but revert the ProcessService changes since the race condition is self-healing and hasn't caused issues in 6 months. * [NOTASK] Refactoring Debug endpoint * fix(security): resolve remaining CodeQL security findings (#2809) * fix(security): resolve remaining CodeQL security findings - gs.service.ts: Use regex on normalized bounded string to prevent ReDoS - spark.service.ts: Add typeof check to prevent parameter tampering - ocp-sticker.service.ts: Use find() to get trusted value from list - olkypay.service.ts: Remove all bracket characters with regex - Add CodeQL config to exclude rpcauth.py (intentional credential output) * fix(bank): remove unnecessary regex escape in olkypay service ESLint no-useless-escape: '[' doesn't need escaping inside character class * style: format olkypay.service.ts * [DEV-4527] delete usedRef when merging with ref user * fix(gs): replace semicolon regex with string loop to avoid CodeQL false positive (#2810) The regex /;*$/ is O(n) and not a ReDoS risk, but CodeQL flags it. Using a while loop with endsWith() achieves the same result without triggering the static analysis warning. * Add userNonce to EIP-7702 delegation data (#2813) * Add userNonce to EIP-7702 delegation data for correct authorization signing The EIP-7702 authorization signature requires the user's current account nonce. Previously this was not provided by the API, causing transactions to fail when the user had already made EIP-7702 transactions (nonce > 0). Changes: - Make prepareDelegationData async to fetch user's account nonce from chain - Add userNonce field to Eip7702DelegationDataDto - Update sell.service.ts and swap.service.ts to await and include userNonce * Add userNonce to EIP-7702 delegation data for correct authorization signing The EIP-7702 authorization signature requires the user's current account nonce. Previously this was not provided by the API, causing transactions to fail when the user had already made EIP-7702 transactions (nonce > 0). Changes: - Make prepareDelegationData async to fetch user's account nonce from chain - Add userNonce field to Eip7702DelegationDataDto - Update sell.service.ts and swap.service.ts to await and include userNonce - Add getTransactionCount mock to all viem test mocks - Add comprehensive tests for prepareDelegationData * Disable EIP-7702 delegation for sell/swap transactions (#2816) The manual signing approach (eth_sign + eth_signTypedData_v4) doesn't work because eth_sign is disabled by default in MetaMask. This needs to be re-implemented using Pimlico's ERC-7677 paymaster service. Changes: - isDelegationSupported() now returns false unconditionally - confirmSell/confirmSwap reject eip7702 input with helpful error message * test(eip7702): skip tests while delegation is disabled (#2817) isDelegationSupported() now returns false for all chains. Tests will be re-enabled when EIP-7702 delegation is reactivated. * Add RealUnit sell endpoint with EIP-7702 support (#2818) Add new sell endpoints for RealUnit token trading: - PUT /realunit/sellPaymentInfo: Returns EIP-7702 delegation data for gasless REALU transfer plus fallback deposit info - PUT /realunit/sell/:id/confirm: Confirms sell with EIP-7702 signatures or manual transaction hash Key features: - Always returns both EIP-7702 data and fallback deposit address - RealUnit app supports eth_sign, so EIP-7702 is always available - Uses existing SellService infrastructure for route management - Creates TransactionRequest for tracking sell transactions New files: - realunit-sell.dto.ts: Request/response DTOs for sell endpoints Modified files: - realunit.controller.ts: Added sellPaymentInfo and confirm endpoints - realunit.service.ts: Added getSellPaymentInfo and confirmSell methods - realunit.module.ts: Added SellCryptoModule and Eip7702DelegationModule * [NOTASK] remove unused service import * fix(realunit): add security validation for sell confirmation (#2819) * fix(realunit): add security validation for sell confirmation - Validate delegation.delegator matches user address (defense-in-depth) - Validate transaction hash format for manual fallback (0x + 64 hex chars) * Move txHash validation to DTO - Add @matches decorator to txHash field in RealUnitSellConfirmDto - Remove redundant runtime validation from confirmSell() service method - DTO validation is the appropriate layer for input format checks * feat: Replace EIP-7702 eth_sign with EIP-5792 wallet_sendCalls (#2822) * feat: replace EIP-7702 eth_sign with EIP-5792 wallet_sendCalls Replace the EIP-7702 delegation approach (which required eth_sign) with EIP-5792 wallet_sendCalls with paymasterService capability for gasless transactions. Changes: - Add PimlicoPaymasterService for ERC-7677 paymaster URL generation - Update sell/swap services to provide EIP-5792 data instead of EIP-7702 - Add txHash field to ConfirmDto for receiving tx hash from wallet_sendCalls - Add handleTxHashInput to track sponsored transfers - Add SPONSORED_TRANSFER PayInType The new flow: 1. Backend provides paymasterUrl and calls array in response 2. Frontend uses wallet_sendCalls with paymasterService capability 3. Wallet handles EIP-7702 internally with paymaster sponsorship 4. Frontend confirms with txHash after transaction is sent This avoids the eth_sign requirement which is disabled by default in MetaMask. * chore: add pimlicoApiKey to config - Add PIMLICO_API_KEY configuration to config.ts and .env.example - Update PimlicoPaymasterService to use config instead of direct env access * test: add PimlicoPaymasterService unit tests - Test isPaymasterAvailable for supported/unsupported blockchains - Test getBundlerUrl returns correct Pimlico URLs for all chains - Test behavior when API key is not configured - Cover Ethereum, Arbitrum, Optimism, Polygon, Base, BSC, Gnosis, Sepolia * feat: differentiate trading errors by KYC level (#2823) Split TRADING_NOT_ALLOWED into specific errors: - RECOMMENDATION_REQUIRED: KycLevel >= 10, missing tradeApprovalDate - EMAIL_REQUIRED: KycLevel < 10, missing email This allows the frontend to redirect users to the appropriate KYC step instead of showing a generic error message. * test(realunit): add comprehensive unit tests for RealUnitDevService (#2801) Add 17 unit tests covering: - Environment checks (PRD skips, DEV/LOC execute) - Asset lookup (mainnet/sepolia REALU) - No waiting requests handling - Buy route not found - Duplicate prevention via txInfo field - Fiat/Bank not found cases - Bank selection (YAPEAL for CHF, OLKYPAY for EUR) - Full simulation flow (BankTx, BuyCrypto, Transaction, TransactionRequest) - Multiple request processing - Error handling (continues on failure) Coverage: 98.73% statements, 100% branches, 100% functions * style(realunit): fix prettier formatting in dev service tests * feat: auto-fill BuyFiat creditor data in FiatOutput (#2824) * feat: auto-fill BuyFiat creditor data in FiatOutput Automatically populate creditor fields (name, address, zip, city, country, currency, amount) from seller's UserData when creating FiatOutput for BuyFiat type. Changes: - fiat-output.service.ts: Extend createInternal() to populate creditor data from buyFiat.sell.user.userData for new BuyFiat FiatOutputs - buy-fiat-preparation.service.ts: Add required relations (userData, country, organizationCountry, outputAsset) to addFiatOutputs() query The bank (Yapeal) requires these fields for payment transmission. Previously admins had to manually set them via PUT /fiatOutput/:id. * feat: validate required creditor fields when creating FiatOutput Add validation to ensure currency, amount, name, address, houseNumber, zip, city, and country are provided when creating any FiatOutput. Throws BadRequestException with list of missing fields if validation fails. * feat: add iban to required creditor fields - Add iban to validation check - Auto-fill iban from sell route in createInternal for BuyFiat * feat: use payoutRoute IBAN for PaymentLink BuyFiats For PaymentLinkPayment: get IBAN from payoutRouteId in link config instead of the sell route. Falls back to sell.iban if no payoutRouteId. * feat: make creditor fields required in CreateFiatOutputDto Mark currency, amount, name, address, houseNumber, zip, city, country, iban as @isnotempty() instead of @IsOptional(). * fix: make houseNumber optional houseNumber should be provided when available but is not required. * feat: skip creditor validation for BANK_TX_RETURN Admin must provide creditor fields manually via DTO. Added TODO for future implementation. * feat: add bank-refund endpoint with required creditor fields - Add BankRefundDto with required creditor fields (name, address, zip, city, country) - Add PUT /transaction/:id/bank-refund endpoint for bank refunds - Extend BankTxRefund with creditor fields - Update refundBankTx to pass creditor data to FiatOutput - Extend createInternal with optional inputCreditorData parameter Frontend must use bank-refund endpoint and provide creditor data for bank transaction refunds to meet bank requirements. * feat: add creditor fields to UpdateBuyCryptoDto for admin flow - Add chargebackCreditorName, chargebackCreditorAddress, chargebackCreditorHouseNumber, chargebackCreditorZip, chargebackCreditorCity, chargebackCreditorCountry to DTO - Update buy-crypto.service to use DTO fields without fallback - Update bank-tx-return.service to pass creditor data to FiatOutput Admin must provide creditor data explicitly for BUY_CRYPTO_FAIL refunds. * refactor: remove bankTx fallbacks for creditor data Creditor fields must be provided explicitly via DTO. BankRefundDto enforces required fields, fallbacks were never used. * fix: add missing SellRepository to FiatOutputModule (#2825) Commit e3f815b added SellRepository injection to FiatOutputService but forgot to add it as a provider in FiatOutputModule, causing the API to crash on startup with dependency resolution error. * feat: EIP-7702 gasless transaction support via DFX relayer (#2826) * feat: add EIP-7702 gasless transaction support via DFX relayer - Add PimlicoBundlerService for EIP-7702 gasless transactions - prepareAuthorizationData(): creates typed data for frontend signing - executeGaslessTransfer(): submits tx with user's signed authorization - hasZeroNativeBalance(): checks if user needs gasless flow - Add GaslessTransferDto and Eip7702AuthorizationDto for request validation - Update SellPaymentInfoDto with gaslessAvailable and eip7702Authorization fields - Add POST /sell/paymentInfos/:id/gasless endpoint for gasless execution - Update sell.service.ts to: - Check user's native balance when creating payment info - Include gasless data in response when user has 0 ETH - Execute gasless transfers via DFX relayer Flow: User signs EIP-7702 authorization off-chain, DFX relayer submits the transaction and pays gas fees. * fix: apply Prettier formatting * feat: auto-fill and validate creditor fields for FiatOutput (#2828) * feat: auto-fill BuyFiat creditor data in FiatOutput Automatically populate creditor fields (name, address, zip, city, country, currency, amount) from seller's UserData when creating FiatOutput for BuyFiat type. Changes: - fiat-output.service.ts: Extend createInternal() to populate creditor data from buyFiat.sell.user.userData for new BuyFiat FiatOutputs - buy-fiat-preparation.service.ts: Add required relations (userData, country, organizationCountry, outputAsset) to addFiatOutputs() query The bank (Yapeal) requires these fields for payment transmission. Previously admins had to manually set them via PUT /fiatOutput/:id. * feat: validate required creditor fields when creating FiatOutput Add validation to ensure currency, amount, name, address, houseNumber, zip, city, and country are provided when creating any FiatOutput. Throws BadRequestException with list of missing fields if validation fails. * feat: add iban to required creditor fields - Add iban to validation check - Auto-fill iban from sell route in createInternal for BuyFiat * feat: use payoutRoute IBAN for PaymentLink BuyFiats For PaymentLinkPayment: get IBAN from payoutRouteId in link config instead of the sell route. Falls back to sell.iban if no payoutRouteId. * feat: make creditor fields required in CreateFiatOutputDto Mark currency, amount, name, address, houseNumber, zip, city, country, iban as @isnotempty() instead of @IsOptional(). * fix: make houseNumber optional houseNumber should be provided when available but is not required. * feat: skip creditor validation for BANK_TX_RETURN Admin must provide creditor fields manually via DTO. Added TODO for future implementation. * feat: add bank-refund endpoint with required creditor fields - Add BankRefundDto with required creditor fields (name, address, zip, city, country) - Add PUT /transaction/:id/bank-refund endpoint for bank refunds - Extend BankTxRefund with creditor fields - Update refundBankTx to pass creditor data to FiatOutput - Extend createInternal with optional inputCreditorData parameter Frontend must use bank-refund endpoint and provide creditor data for bank transaction refunds to meet bank requirements. * feat: add creditor fields to UpdateBuyCryptoDto for admin flow - Add chargebackCreditorName, chargebackCreditorAddress, chargebackCreditorHouseNumber, chargebackCreditorZip, chargebackCreditorCity, chargebackCreditorCountry to DTO - Update buy-crypto.service to use DTO fields without fallback - Update bank-tx-return.service to pass creditor data to FiatOutput Admin must provide creditor data explicitly for BUY_CRYPTO_FAIL refunds. * refactor: remove bankTx fallbacks for creditor data Creditor fields must be provided explicitly via DTO. BankRefundDto enforces required fields, fallbacks were never used. * feat: store creditor data in entity for later admin approval - Add chargebackCreditor* fields to BuyCrypto and BankTxReturn entities - Extend chargebackFillUp methods to accept and store creditor data - Update refundBankTx to save customer-provided creditor data - Use stored entity fields as fallback in admin flow Flow: Customer provides creditor data via /bank-refund endpoint, data is stored in entity. Admin later approves with chargebackAllowedDate, using stored creditor data (or can override via DTO). * refactor: consolidate creditor fields into single JSON column (#2829) - Replace 6 chargebackCreditor* columns with one chargebackCreditorData JSON column - Add CreditorData interface for type safety - Add creditorData getter for JSON parsing - Update BuyCrypto and BankTxReturn entities - Update buy-crypto.service to use creditorData getter - Add migration to add new column and drop old columns This reduces schema complexity and aligns with existing JSON patterns in the codebase (priceSteps, config, etc.). * chore: remove allowlist and bank endpoints. (#2827) * [NOTASK] remove unused import * feat: EIP-7702 gasless via Pimlico ERC-4337 (all chains) (#2834) * feat: implement EIP-7702 gasless via Pimlico ERC-4337 - Replace SimpleDelegation with MetaMask Delegator (0x63c0c19a...) - Deployed on ALL major EVM chains (not just Sepolia) - Uses onlyEntryPointOrSelf modifier for security - Implement ERC-4337 UserOperation submission via Pimlico Bundler - factory=0x7702 signals EIP-7702 UserOperation - Pimlico Paymaster sponsors gas fees - EntryPoint v0.7 (0x0000000071727De22E5E9d8BAf0edAc6f37da032) - Flow: User signs EIP-7702 authorization -> Backend creates UserOp -> Pimlico Bundler submits -> EntryPoint calls execute() on EOA -> Token transfer FROM user (gas paid by Pimlico) Supported chains: Ethereum, Arbitrum, Optimism, Polygon, Base, BSC, Gnosis, Sepolia * fix: add missing evm-chain.config.ts and fix lint warnings * [NO-TASK] Cleanup * fix: add creditor data fallback in refundBankTx methods (#2835) When batch job or admin calls refundBankTx() without creditor data in DTO, use stored creditorData from entity as fallback for FiatOutput creation. Fixed in: - BuyCryptoService.refundBankTx(): fallback to buyCrypto.creditorData - BankTxReturnService.refundBankTx(): fallback to bankTxReturn.creditorData Added unit tests for BankTxReturnService creditor data fallback. * [NO-TASK] Cleanup 2 * [NO-TASK] Cleanup 3 * fix: always show fixed IBAN and name for bank refunds (#2836) getRefundTarget now always returns bankTx.iban for bank transactions, ensuring the frontend displays IBAN and name as fixed values instead of showing editable input fields. The refund must always go back to the original sender's bank account, so allowing users to change the IBAN was incorrect behavior. * feat(eip7702): Add integration tests for gasless E2E flow (#2837) * feat(eip7702): add integration tests for gasless E2E flow Add integration tests for EIP-7702 gasless transaction flow: - gasless-e2e.integration.spec.ts: End-to-end flow test - pimlico-bundler.integration.spec.ts: Bundler API integration tests Tests verify: - Transaction request creation with delegation - Pimlico bundler UserOp submission - Sponsored transaction handling - EIP-7702 capability detection Requires PIMLICO_API_KEY environment variable * fix(eip7702): fix lint/format issues in integration tests - Add viem import at top level instead of inline require() - Remove unused ENTRY_POINT_V07 and METAMASK_DELEGATOR constants * fix: improve refund flow validation and error handling (#2838) - Enable BANK_TX_RETURN validation in FiatOutput (was skipped with TODO) - Add JSON.parse error handling for creditorData in BankTxReturn entity - Add @isiban validation to refundIban in RefundInternalDto * fix(sell,swap): only include eip5792 data when user has zero native balance (#2839) Previously, depositTx.eip5792 was always included when Pimlico paymaster was available, regardless of whether the user actually needed gasless transactions. This caused issues because: 1. Frontend checked for eip5792 presence, not gaslessAvailable flag 2. Older wallets (MetaMask <12.20) don't support EIP-5792 3. Users with ETH balance received unnecessary paymaster data Changes: - sell.service.ts: Move balance check before createDepositTx() - sell.service.ts: Pass hasZeroBalance to createDepositTx() - sell.service.ts: Only add eip5792 when includeEip5792=true - swap.service.ts: Add includeEip5792 parameter (default: false) Now eip5792 data is only included when gaslessAvailable=true, making the API response consistent and predictable. * fix: critical refund flow bugs - inverted validation and field fallback (#2840) * fix: improve refund flow validation and error handling - Enable BANK_TX_RETURN validation in FiatOutput (was skipped with TODO) - Add JSON.parse error handling for creditorData in BankTxReturn entity - Add @isiban validation to refundIban in RefundInternalDto * fix: critical refund flow bugs - inverted validation and field fallback BUG #1: Fix isRefundDataValid() inverted logic - Changed condition from `<= 0` to `> 0` - Previously: accepted expired refunds, rejected valid ones - Now: correctly validates refund expiry BUG #2: Fix bankFields fallback not working - Changed from conditional object (all-or-nothing based on name) - Now: includes all provided fields independently - Previously: if name was empty, ALL fields were discarded BUG #5: Add whitespace validation for creditor fields - Added trim() check for string fields - Previously: whitespace-only strings ' ' passed validation * revert: isRefundDataValid was correct, rollback wrong fix After deeper analysis of Util.secondsDiff(): - secondsDiff(expiryDate) = (Date.now() - expiryDate) / 1000 - If expiryDate is in FUTURE: result is NEGATIVE - If expiryDate is in PAST: result is POSITIVE Original `<= 0` is CORRECT: - Future (valid) → negative → <= 0 is TRUE → valid ✓ - Past (expired) → positive → <= 0 is FALSE → invalid ✓ The previous commit incorrectly changed this to `> 0`. * feat(swap): add gasless transaction support for Swap flow (#2841) - Add gaslessAvailable and eip7702Authorization fields to SwapPaymentInfoDto - Implement balance-check in toPaymentInfoDto() using PimlicoBundlerService - Add EIP-7702 authorization handling in confirmSwap() - Add unit tests for SellService and SwapService createDepositTx method * ci: optimize workflow step order and remove redundant type-check (#2843) - Remove redundant type-check step (build already runs tsc) - Reorder steps for fail-fast: lint → format → build → test - Clean up multiline run commands to single line This saves ~20s per run and up to 2 minutes on early failures. * feat(aml): skip phone verification for users referred by trusted referrers (#2845) * feat(aml): skip phone verification for users referred by trusted referrers Add isTrustedReferrer flag to UserData. Users who were referred by a trusted referrer (usedRef points to a user with isTrustedReferrer=true) are exempt from the phone verification check for users over 55. * test(aml): add comprehensive tests for isTrustedReferrer phone verification exemption 18 test cases covering: - Trusted referrer skips phone verification - Untrusted/no referrer requires phone verification - All edge cases (age boundaries, missing data, account types) - Truth table for refUser.userData.isTrustedReferrer values - Verification that other conditions remain unaffected * [NO-TASK] Fixed migration --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Co-authored-by: Lam Nguyen <32935491+xlamn@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com>
* [DEV-4531] unassignedTx with vIban (#2833) * [DEV-4531] unassignedTx with vIban * fix: add VirtualIbanService mock to transaction controller test --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> * ci: add PR review bot workflow (#2842) * ci: add PR review bot workflow Automated PR review comments for: - Unverified (unsigned) commits - Non-conventional commit messages - ESLint warnings/errors - TypeScript errors - npm audit vulnerabilities (high/critical) - New TODO/FIXME comments in diff * fix(ci): use env vars to avoid JavaScript syntax errors in github-script Pass step outputs through env block instead of direct template substitution. This prevents syntax errors when outputs contain backticks, newlines, or other special characters that break JavaScript template literals. * feat: add debug scripts and improve restricted column handling (#2847) * feat: add database debug script for DEBUG role users - Add db-debug.sh script for executing SQL queries via /gs/debug endpoint - Add .env.db-debug.sample with configuration template - Update .gitignore to exclude .env.* files but include .sample files Usage: ./scripts/db-debug.sh "SELECT TOP 10 id FROM asset" * docs: add debug endpoint documentation and log query script - Add DEBUG-ENDPOINT.md with complete setup instructions - Add log-debug.sh for Azure Application Insights queries - Document required Azure environment variables - Include usage examples and troubleshooting guide * feat: show NULL vs SET for restricted debug columns Change masking from [RESTRICTED] to: - [RESTRICTED:NULL] when value is null/undefined - [RESTRICTED:SET] when value is present This helps debugging without exposing sensitive data. * security: block chargebackCreditorData from debug endpoint Add chargebackCreditorData to blocked columns for: - bank_tx_return - buy_crypto This field contains personal data (name, address, zip, city, country) that should not be visible via the debug endpoint. --------- Co-authored-by: Yannick <52333989+Yannick1712@users.noreply.github.com> Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
Release: develop -> master
Release: develop -> master
* fix(pimlico): use zero address instead of empty hex for initial paymaster (#2853) Pimlico's pm_sponsorUserOperation validates the paymaster field and rejects '0x' as an invalid address. Use the proper zero address '0x0000000000000000000000000000000000000000' instead. * perf: reduce addFiatOutputs interval from 10min to 1min (#2857) Reduce the cronjob interval for FiatOutput creation from EVERY_10_MINUTES to EVERY_MINUTE, cutting maximum wait time by 90%. * fix: persist Yapeal API errors to fiat_output.info column (#2859) * fix: persist Yapeal API errors to fiat_output.info column When Yapeal payment transmission fails, the error message is now stored in the info column for debugging. Previously errors were only logged, making it difficult to diagnose repeated failures. * fix: limit error message to 256 chars (column length) and add error handling - Fix: info column is limited to 256 chars, not 500 - Add try-catch around DB update to prevent loop interruption * refactor: only persist error if info field is empty Avoids unnecessary DB updates on every cron run * fix: clear YAPEAL error from info field on successful transmission * [NO-TASK] Fixed low liquidity transaction priorization * feat: add automatic chargeback processing for bank_tx_return (#2848) * feat: add automatic chargeback processing for bank_tx_return Add chargebackTx() cronjob that automatically approves refunds when: - User has confirmed (chargebackAllowedDateUser is set) - Amount is set (chargebackAmount) - IBAN is set (chargebackIban) - No output created yet (chargebackOutput is null) - User status is OK (not blocked, valid KYC/risk status) This aligns bank_tx_return with buy_crypto/buy_fiat behavior where refunds are automatically processed after user confirmation. * fix: add user.status check to chargebackTx for consistency Add transaction.user.status check to align with buy_crypto and buy_fiat chargebackTx implementations. Only process refunds when user status is NA or ACTIVE, preventing automatic refunds for blocked/deleted users. * Fixed app insights query --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com>
Release: develop -> master
…und-ownership-check (#2863) fix: correct ownership check for unassigned transaction refunds Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
* fix: improve refund cronjob validation (#2866) * fix: allow BankTxReturn refund without userData The chargebackTx cronjob now handles two cases: 1. Entries WITH userData: check KYC/risk status as before 2. Entries WITHOUT userData: process without KYC/risk check This enables automatic refunds for unassigned deposits that have no associated user account. * fix: require creditorData for automatic refund processing Cronjob now only processes entries where chargebackCreditorData is set. This prevents unnecessary errors from validateRequiredCreditorFields. * fix: require creditorData for BuyCrypto bank refund processing Cronjob now only processes bank refunds where chargebackCreditorData is set. Checkout refunds don't need creditorData (handled by checkout provider). * fix: exclude 4xx client errors from Application Insights failures (#2865) * fix: exclude 4xx client errors from Application Insights failures Add TelemetryProcessor to mark 4xx responses as success=true. Only 5xx server errors should appear in the Failures dashboard. This reduces noise from expected client errors (400 Bad Request, 401 Unauthorized, 404 Not Found) in failure metrics and alerts. * fix: use correct type for responseCode (string, not number) Application Insights SDK types define responseCode as string. Use parseInt() for proper type conversion before comparison. * [NO-TASK] Minor improvements --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com>
Release: develop -> master
* fix: use eth chain for sell endpoint. (#2872) * fix: use eth for delegation check. (#2875) * fix: round FiatOutput amount to 2 decimal places (#2876) Add Util.round(amount, 2) when setting FiatOutput.amount in: - create(): after entity creation from DTO - createInternal(): when calculating from buyFiats and before save - update(): before saving DTO amount Fiat amounts must always be rounded to 2 decimal places for correct bank transaction processing. * fix: case-insensitive bankUsage matching in findMatchingBuy (#2877) * fix: case-insensitive bankUsage matching in findMatchingBuy The remittanceInfo was compared case-sensitively with bankUsage, causing transactions with lowercase usage codes (e.g. 6ed3-090b-25a8) to not match their routes (stored as 6ED3-090B-25A8). Add .toUpperCase() to normalized candidate for consistent matching. * fix: correct order of toUpperCase and O-to-0 replacement Move toUpperCase() before replace(/O/g, '0') so that lowercase 'o' is first converted to 'O', then replaced with '0'. This handles edge cases like '6ed3-o90b-25a8' where user types lowercase 'o' instead of '0'. * Refactoring * Refactoring 2 * [NOTASK] add bankDataUserMismatch auto fail * Bank refund checks (#2880) * fix: improved bank refund * fix: enforce creditor data for bank refunds * fix: tests * feat: add Special ZCHF 0.5% fee for userData 363001 (#2886) * feat: add Special ZCHF 0.5% fee for userData 363001 Add migration that: - Creates new 'Special ZCHF 0.5%' fee (type: Special, rate: 0.005) - Applies to all ZCHF chains: Ethereum, Polygon, Arbitrum, Optimism, BSC, Base - Assigns fee to userData 363001 via individualFees field This reduces the fee for all ZCHF buy/sell/swap transactions from the standard Organization rate (1.99%-2.49%) to 0.5%. * fix: correct blockchainFactor and add financialTypes to fee migration - Change blockchainFactor from 1 to 0 (consistent with Fee 67, 111) - Add financialTypes: 'CHF' (consistent with existing ZCHF fees) - Use unique label 'Special ZCHF 0.5% UserData 363001' to avoid collisions - Fix down() migration: use STUFF/LEFT instead of fragile SUBSTRING --------- Co-authored-by: Lam Nguyen <32935491+xlamn@users.noreply.github.com> Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com> Co-authored-by: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Co-authored-by: David May <85513542+davidleomay@users.noreply.github.com>
* feat: add userData 301484 to Special ZCHF 0.5% fee (#2887) - Rename fee label from 'Special ZCHF 0.5% UserData 363001' to 'Special ZCHF 0.5%' - Assign existing fee to userData 301484 via individualFees Same 0.5% ZCHF fee now applies to both userData 363001 and 301484. * fix: remove incorrect VIDEO_IDENT_REQUIRED check for organizations (#2885) The Organization-specific VIDEO_IDENT_REQUIRED rule was blocking Organizations with OnlineId even when they had valid BankTxVerification. The existing BANK_TRANSACTION_OR_VIDEO_MISSING rule already covers all cases correctly: - Sell (not CHF) > 1000 CHF without BankTxVerification → Bank TX or Video - Card payment > 1000 CHF without BankTxVerification → Bank TX or Video - Swap > 1000 CHF without BankTxVerification → Bank TX or Video Removed: - VIDEO_IDENT_REQUIRED QuoteError enum value - Organization-specific VIDEO_IDENT_REQUIRED check - Unused KycIdentificationType import --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
Release: develop -> master
Release: develop -> master
* fix: apply npm audit security fixes (#2893) Update transitive dependencies to address 3 security vulnerabilities (1 low, 2 high) identified by npm audit. Co-authored-by: Bernd <bernd@MacBook-DFX-Bernd-2026.local> * fix: bank refund creditor data fix --------- Co-authored-by: bernd2022 <104787072+bernd2022@users.noreply.github.com> Co-authored-by: Bernd <bernd@MacBook-DFX-Bernd-2026.local> Co-authored-by: David May <david.leo.may@gmail.com>
* chore: add CODEOWNERS file (#2898) Require approval from @davidleomay and @TaprootFreak for all PRs. * chore: remove footer text from PR Review Bot (#2902) * chore: remove footer text from PR Review Bot * chore: remove header from PR Review Bot comments * fix: include all comment types in bot comment detection --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
* chore: rename master branch references to main (#2900) * chore: rename master branch references to main Update all workflow files to use 'main' instead of 'master': - api-prd.yaml: trigger on main branch - api-pr.yaml: run PR checks for main branch - codeql.yml: scan main branch - auto-release-pr.yaml: create release PRs to main * docs: fix CitreaScan branch reference (master -> main) * fix: load wallet relation for autoTradeApproval check in mail login (#2904) In completeSignInByMail(), the wallet relation was not loaded when fetching userData, causing the autoTradeApproval check in checkPendingRecommendation() to always fail. Changes: - Add wallet to relations in getUserData() call - Pass account.wallet to checkPendingRecommendation() This aligns mail-login with wallet-login behavior where the wallet is properly passed to checkPendingRecommendation(). * feat: improve local development experience for mail handling (#2905) - Skip mail sending in local environment and log mail details instead - Log mail login URL in local environment for easy testing - Add SERVICES_URL to .env.local.example for complete login URLs * fix: initialize KYC progress on mail login to set kycLevel 10 (#2903) * fix: initialize KYC progress on mail login to set kycLevel 10 Mail login users had kycLevel 0 even though their email was verified via OTP. This happened because the KYC flow was never triggered after mail login, leaving CONTACT_DATA step uncompleted. Changes: - Add initializeProgress() method to KycService that triggers updateProgress() for a given user - Call initializeProgress() in completeSignInByMail() after successful authentication Now when a user completes mail login: 1. initializeProgress() triggers updateProgress() 2. CONTACT_DATA step is auto-completed (user.mail exists) 3. PERSONAL_DATA becomes next step → kycLevel set to 10 This makes mail login behavior consistent with wallet login where adding an email triggers the same KYC flow. * fix: improve initializeProgress with retry logic and error handling - Set shouldContinue=false to only set kycLevel without initiating next KYC steps (PERSONAL_DATA) - Add Util.retry() with duplicate key check for race conditions (e.g., user double-clicks OTP link) - Make KYC initialization non-blocking in completeSignInByMail() so login succeeds even if KYC init fails * fix: correct initializeProgress to use autoStep=false The previous fix with shouldContinue=false was incorrect - it prevented any KYC progress from happening because CONTACT_DATA doesn't return a nextLevel value. The correct solution is shouldContinue=true, autoStep=false: - shouldContinue=true: allows CONTACT_DATA to be initiated and auto-completed - autoStep=false: prevents PERSONAL_DATA from being initiated (depth > 0) Flow: 1. depth=0: (autoStep || depth===0) = true → CONTACT_DATA initiated/completed 2. depth=1: (autoStep || depth===0) = false → Level 10 set, no further steps * fix: skip initializeProgress for users with CONTACT_DATA completed Prevents unintentionally initiating PERSONAL_DATA step for returning users who already have CONTACT_DATA completed. The level should already be set for these users. * chore: add migration script to fix kycLevel for edge case users 4 active users have CONTACT_DATA completed but kycLevel = 0. This SQL script updates their level to 10. Affected user IDs: 257036, 229330, 1158, 1058 * fix: make migration script safer - Comment out UPDATE statement (must be uncommented manually) - Add transaction wrapper (BEGIN/COMMIT/ROLLBACK) - Use JOIN-based UPDATE syntax for SQL Server - Add clear step-by-step instructions - Add row count verification check * fix: Start KYC process on mail add * fix: script executed --------- Co-authored-by: David May <david.leo.may@gmail.com> --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: bernd2022 <104787072+bernd2022@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com>
Release: develop -> main
Release: develop -> main
Release: develop -> main
* feat(liquidity-management): add swap command to DfxDexAdapter (#2882) * feat(liquidity-management): add swap command to DfxDexAdapter Add new 'swap' command for cross-asset liquidity acquisition via DEX. Unlike 'purchase' (same asset), 'swap' allows converting one asset to another, e.g., USDC → EURC via Uniswap. - Add SWAP to DfxDexAdapterCommands enum - Implement swap() method with source asset from params - Add param validation for sourceAsset parameter - Reuse checkSellPurchaseCompletion for order tracking Usage: Action params {"sourceAsset": "USDC"} with rule targetAsset EURC will swap available USDC to EURC via the configured DEX pool. * refactor: consolidate SWAP into PURCHASE/SELL with tradeAsset parameter - Remove SWAP command from DfxDexAdapterCommands enum - Add optional tradeAsset parameter to PURCHASE and SELL commands - Add resolveTradeAsset() helper for cross-asset operations - Add validateTradeAssetParams() for parameter validation When tradeAsset is provided, the command uses it as the source asset for cross-asset operations (e.g., USDC → EURC via DEX). When not provided, behavior remains unchanged (same-asset operation). This creates a symmetric API where both PURCHASE and SELL support cross-asset operations through a single optional parameter. * refactor: simplify tradeAsset - only for PURCHASE, not SELL - Remove tradeAsset support from SELL (sellLiquidity not implemented for any asset) - Simplify return type to Asset instead of Awaited<ReturnType<...>> - Keep SELL with original simple implementation * perf: avoid unnecessary async call when no tradeAsset provided * style: fix prettier formatting * feat: cleanup + added sell * fix: fixed swap amounts --------- Co-authored-by: David May <david.leo.may@gmail.com> * [DEV-4424] Implemented forwarded pay-in return (#2913) * [DEV-4424] Implemented forwarded pay-in return * [DEV-4424] Fix tests * feat(aml): add NAME_TOO_SHORT check for bank payout validation (#2879) * feat(aml): add NAME_TOO_SHORT check for bank payout validation Add AML check to reject transactions where the user's name contains fewer than 4 letters. Banks require a minimum name length for processing. Changes: - Add AmlError.NAME_TOO_SHORT with CRUCIAL type and FAIL status - Add AmlReason.NAME_TOO_SHORT - Add countLetters() helper to count only alphabetic characters - Add name length validation in getAmlErrors() after NAME_MISSING check - Update SiftAmlDeclineMap and TransactionReasonMapper The check uses verifiedName, bankData.name, or completeName (in that order) and counts only letters (including European special characters like ä, ö, ü, ß). * feat(i18n): add name_too_short chargeback reason translations Add email translations for NAME_TOO_SHORT AML reason in all 6 languages: - EN, DE, FR, IT, ES, PT This text is shown to users when their transaction is refunded due to the account holder name having fewer than 4 letters, which banks require for processing payouts. * fix: use Unicode property escape for letter counting Replace hardcoded character list with \p{L} Unicode property escape to correctly count letters in all languages (Scandinavian, Polish, Czech, Turkish, etc.). Before: 'Åse Ødegård' counted as 6 letters (å, Ø ignored) After: 'Åse Ødegård' counted as 10 letters (correct) * fix: use Sepolia blockchain for REALU on DEV/LOC (#2915) * fix: use Sepolia blockchain for REALU on DEV/LOC On DEV and LOC environments, REALU transactions were being broadcast to Ethereum Mainnet instead of Sepolia testnet. This caused the sell confirm flow to fail since actual tokens are on Sepolia. Change tokenBlockchain to be environment-aware: use Sepolia on DEV/LOC, Ethereum on PROD/STG. * fix: support Sepolia for EIP-7702 delegation on DEV/LOC Update isDelegationSupportedForRealUnit() to accept Sepolia blockchain on DEV/LOC environments. Without this, the EIP-7702 transfer would fail with 'delegation not supported' error even though the asset blockchain is correctly set to Sepolia. * fix: update buy simulation to use Sepolia REALU on DEV/LOC Since TransactionRequests are now created with Sepolia REALU asset, the buy simulation must also search for Sepolia REALU targetId. - Remove mainnet REALU lookup (no longer needed) - Search for Sepolia REALU targetId instead of mainnet - Update tests to match new behavior * fix: always use Mainnet asset for REALU price lookups Price data is only available for Mainnet REALU asset. Add separate getMainnetRealuAsset() method for price-related functions while keeping getRealuAsset() environment-based for transactions. - getRealUnitPrice() now uses Mainnet asset - getHistoricalPrice() now uses Mainnet asset - Transaction methods (buy/sell) still use environment-based asset * refactor RealUnitDevService variables. * chore: revert fetch prices only from mainnet. --------- Co-authored-by: TuanLamNguyen <xnguyen.lam@gmail.com> * fix(bank-data): transform empty string names to null in DTOs (#2918) Empty strings in bankData.name bypass nullish coalescing fallback logic because ?? treats "" as a present value. This causes incorrect behavior in AML name resolution where empty strings are used instead of actual user data. Add @Transform decorator to name field in CreateBankDataDto and UpdateBankDataDto that trims whitespace and converts empty strings to null, preventing invalid data at the source. Closes #2911 * Update XT/DEURO liquidity minimum from 4300 to 10000 (#2920) --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com> Co-authored-by: David May <85513542+davidleomay@users.noreply.github.com> Co-authored-by: TuanLamNguyen <xnguyen.lam@gmail.com> Co-authored-by: bernd2022 <104787072+bernd2022@users.noreply.github.com> Co-authored-by: Danswar <48102227+Danswar@users.noreply.github.com>
Release: develop -> main
Release: develop -> main
* fix(security): disable unused urlencoded parser and patch CVE-2024-45590 & CVE-2025-15284 (#2925) - Add body-parser 1.20.3 override to fix CVE-2024-45590 (DoS via deep nesting) - Add qs ^6.14.1 override to fix CVE-2025-15284 (arrayLimit bypass) - Disable automatic bodyParser in NestFactory.create() to remove unused urlencoded attack surface Closes #2921 * [DEV-3526] Add automatic liquidity pipeline for ref payouts (#2672) * feat(ref-reward): Add automatic liquidity pipeline for ref payouts When ref reward payouts lack sufficient liquidity, automatically trigger the LiquidityManagement pipeline (similar to BuyCrypto). Changes: - Add liquidityPipeline relation to RefReward entity - Extend secureLiquidity() to check available liquidity - Start pipeline via liquidityService.buyLiquidity() when deficit detected - Set status to PENDING_LIQUIDITY before pipeline attempt (consistent with BuyCrypto) - Process pending rewards when pipeline completes - Reset to PREPARED on pipeline failure for automatic retry Flow: PREPARED → [liquidity check] → PENDING_LIQUIDITY → [pipeline complete] → READY_FOR_PAYOUT * refactor: improve consistency of liquidity pipeline implementation - Add pendingLiquidity() and resetToPrepared() entity methods to RefReward (consistent with existing entity method pattern like readyToPayout(), payingOut()) - Consolidate DB queries: load all rewards in single query instead of 3 separate - Fix error handling: try/catch per individual reward instead of per asset group (consistent with ref-reward-out.service.ts pattern) - Atomize pipeline updates: create pipeline first, then update rewards (avoids inconsistent state where rewards are PENDING_LIQUIDITY without pipeline) - Remove misleading 'consistent with BuyCrypto' comment * fix: change log level to warn for unexpected state Rewards in PENDING_LIQUIDITY without pipeline should never occur with atomic updates. This indicates legacy data or DB issues. * feat: refactoring * feat: added migration --------- Co-authored-by: David May <david.leo.may@gmail.com> * fix: exclude pending deposits from Kraken toKraken balance calculation (#2929) Kraken deposits with status='pending' (On Hold) were incorrectly being counted as "arrived" in the toKraken pending balance calculation. This caused the balance to show ~117k CHF less than actual, because: - 50k CHF On Hold - 30k CHF On Hold - 40k EUR On Hold (~37k CHF) These deposits have not yet been credited to the Kraken account and should not be subtracted from the pending-to-Kraken amount. Add status !== 'pending' filter to both CHF and EUR receiver exchange_tx filters in getFinancialDataLog(). * fix: prioritize user-provided refundTarget over pre-filled value (#2928) When processing refunds, user input (dto.refundTarget) should take priority over the pre-filled value (refundData.refundTarget). This allows customers to override the original IBAN when it's a Multi-Account IBAN that cannot be used for refunds. Changed: - BankTxReturn refund: dto.refundTarget ?? refundData.refundTarget - BuyCrypto bank refund: dto.refundTarget ?? refundData.refundTarget Previously the logic was reversed, ignoring user-provided values when the backend had a pre-filled refundTarget. --------- Co-authored-by: bernd2022 <104787072+bernd2022@users.noreply.github.com> Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com>
Release: develop -> main
Release: develop -> main
Release: develop -> main
Release: develop -> main
Release: develop -> main
Release: develop -> main
Automatically run ESLint and Prettier checks on staged TypeScript files before each commit to prevent CI failures.
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Changes
.husky/pre-commithook that runslint-stagedlint-stagedconfiguration inpackage.jsonhuskyandlint-stagedas dev dependenciesTest plan
npm installto install dependenciesnpm run lint- passesnpm run format:check- passesnpm run build- passes