diff --git a/src/integration/checkout/services/checkout.service.ts b/src/integration/checkout/services/checkout.service.ts index b57d7d7b36..ae793ffa6f 100644 --- a/src/integration/checkout/services/checkout.service.ts +++ b/src/integration/checkout/services/checkout.service.ts @@ -36,6 +36,10 @@ export class CheckoutService { this.checkout = new Checkout(); } + isAvailable(): boolean { + return process.env.CKO_SECRET_KEY != null && Config.checkout.entityId != null; + } + async createPaymentLink( remittanceInfo: string, fiatAmount: number, diff --git a/src/integration/exchange/services/exchange-tx.service.ts b/src/integration/exchange/services/exchange-tx.service.ts index 59f41698c4..10212b0ad7 100644 --- a/src/integration/exchange/services/exchange-tx.service.ts +++ b/src/integration/exchange/services/exchange-tx.service.ts @@ -24,6 +24,8 @@ import { ExchangeRegistryService } from './exchange-registry.service'; export class ExchangeTxService { private readonly logger = new DfxLogger(ExchangeTxService); + private readonly syncWarningsLogged = new Set(); + constructor( private readonly exchangeTxRepo: ExchangeTxRepository, private readonly registryService: ExchangeRegistryService, @@ -171,7 +173,10 @@ export class ExchangeTxService { return transactions; } catch (e) { - this.logger.error(`Failed to synchronize transactions from ${sync.exchange}:`, e); + if (!this.syncWarningsLogged.has(sync.exchange)) { + this.logger.warn(`Failed to synchronize transactions from ${sync.exchange}:`, e); + this.syncWarningsLogged.add(sync.exchange); + } } return []; diff --git a/src/subdomains/core/monitoring/observers/checkout.observer.ts b/src/subdomains/core/monitoring/observers/checkout.observer.ts index 5bad9a248d..cf1f5e0f15 100644 --- a/src/subdomains/core/monitoring/observers/checkout.observer.ts +++ b/src/subdomains/core/monitoring/observers/checkout.observer.ts @@ -20,6 +20,8 @@ interface CheckoutData { export class CheckoutObserver extends MetricObserver { protected readonly logger = new DfxLogger(CheckoutObserver); + private unavailableWarningLogged = false; + constructor( monitoringService: MonitoringService, private readonly checkoutService: CheckoutService, @@ -30,6 +32,14 @@ export class CheckoutObserver extends MetricObserver { @DfxCron(CronExpression.EVERY_MINUTE, { process: Process.MONITORING, timeout: 1800 }) async fetch() { + if (!this.checkoutService.isAvailable()) { + if (!this.unavailableWarningLogged) { + this.logger.warn('Checkout not configured - skipping fetch'); + this.unavailableWarningLogged = true; + } + return []; + } + const data = await this.getCheckout(); this.emit(data); diff --git a/src/subdomains/core/monitoring/observers/payment.observer.ts b/src/subdomains/core/monitoring/observers/payment.observer.ts index 6bc841c96d..ae5ba99576 100644 --- a/src/subdomains/core/monitoring/observers/payment.observer.ts +++ b/src/subdomains/core/monitoring/observers/payment.observer.ts @@ -125,8 +125,8 @@ export class PaymentObserver extends MetricObserver { return { buyCrypto: await this.repos.buyCrypto .findOne({ where: {}, order: { outputDate: 'DESC' } }) - .then((b) => b.outputDate), - buyFiat: await this.repos.buyFiat.findOne({ where: {}, order: { outputDate: 'DESC' } }).then((b) => b.outputDate), + .then((b) => b?.outputDate), + buyFiat: await this.repos.buyFiat.findOne({ where: {}, order: { outputDate: 'DESC' } }).then((b) => b?.outputDate), }; } } diff --git a/src/subdomains/core/payment-link/services/payment-balance.service.ts b/src/subdomains/core/payment-link/services/payment-balance.service.ts index 9426374abb..bf05319207 100644 --- a/src/subdomains/core/payment-link/services/payment-balance.service.ts +++ b/src/subdomains/core/payment-link/services/payment-balance.service.ts @@ -20,6 +20,8 @@ import { Util } from 'src/shared/utils/util'; export class PaymentBalanceService implements OnModuleInit { private readonly logger = new DfxLogger(PaymentBalanceService); + private readonly unavailableWarningsLogged = new Set(); + private readonly chainsWithoutPaymentBalance = [ Blockchain.LIGHTNING, Blockchain.MONERO, @@ -65,17 +67,27 @@ export class PaymentBalanceService implements OnModuleInit { await Promise.all( groupedAssets.map(async ([chain, assets]) => { const client = this.blockchainRegistryService.getClient(chain); + if (!client) { + if (!this.unavailableWarningsLogged.has(chain)) { + this.logger.warn(`Blockchain client not configured for ${chain} - skipping payment balance`); + this.unavailableWarningsLogged.add(chain); + } + return; + } const targetAddress = this.getDepositAddress(chain); + if (!targetAddress) return; const coin = assets.find((a) => a.type === AssetType.COIN); const tokens = assets.filter((a) => a.type !== AssetType.COIN); - balanceMap.set(coin.id, { - owner: targetAddress, - contractAddress: coin.chainId, - balance: await client.getNativeCoinBalanceForAddress(targetAddress), - }); + if (coin) { + balanceMap.set(coin.id, { + owner: targetAddress, + contractAddress: coin.chainId, + balance: await client.getNativeCoinBalanceForAddress(targetAddress), + }); + } if (tokens.length) { try { diff --git a/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts b/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts index b1c4b788c9..4ff089405b 100644 --- a/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts +++ b/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts @@ -85,6 +85,8 @@ export class BankTxService implements OnModuleInit { private readonly logger = new DfxLogger(BankTxService); private readonly bankBalanceSubject: Subject = new Subject(); + private olkyUnavailableWarningLogged = false; + constructor( private readonly bankTxRepo: BankTxRepository, private readonly bankTxBatchRepo: BankTxBatchRepository, @@ -164,7 +166,10 @@ export class BankTxService implements OnModuleInit { const olkyBank = await this.bankService.getBankInternal(IbanBankName.OLKY, 'EUR'); if (!olkyBank) { - this.logger.warn('Olky bank not configured - skipping checkTransactions'); + if (!this.olkyUnavailableWarningLogged) { + this.logger.warn('Olky bank not configured - skipping checkTransactions'); + this.olkyUnavailableWarningLogged = true; + } return; } diff --git a/src/subdomains/supporting/fiat-payin/services/fiat-payin-sync.service.ts b/src/subdomains/supporting/fiat-payin/services/fiat-payin-sync.service.ts index 8603e33715..c56e71ed63 100644 --- a/src/subdomains/supporting/fiat-payin/services/fiat-payin-sync.service.ts +++ b/src/subdomains/supporting/fiat-payin/services/fiat-payin-sync.service.ts @@ -19,6 +19,8 @@ import { CheckoutTxService } from './checkout-tx.service'; export class FiatPayInSyncService { private readonly logger = new DfxLogger(FiatPayInSyncService); + private unavailableWarningLogged = false; + constructor( private readonly checkoutService: CheckoutService, private readonly checkoutTxRepo: CheckoutTxRepository, @@ -32,6 +34,14 @@ export class FiatPayInSyncService { @DfxCron(CronExpression.EVERY_MINUTE, { process: Process.FIAT_PAY_IN, timeout: 1800 }) async syncCheckout() { + if (!this.checkoutService.isAvailable()) { + if (!this.unavailableWarningLogged) { + this.logger.warn('Checkout not configured - skipping syncCheckout'); + this.unavailableWarningLogged = true; + } + return; + } + const syncDate = await this.checkoutTxService.getSyncDate(); const payments = await this.checkoutService.getPayments(syncDate); diff --git a/src/subdomains/supporting/log/log-job.service.ts b/src/subdomains/supporting/log/log-job.service.ts index e5f31b6e3f..d7a495d206 100644 --- a/src/subdomains/supporting/log/log-job.service.ts +++ b/src/subdomains/supporting/log/log-job.service.ts @@ -60,6 +60,8 @@ import { LogService } from './log.service'; export class LogJobService { private readonly logger = new DfxLogger(LogJobService); + private readonly unavailableClientWarningsLogged = new Set(); + constructor( private readonly tradingRuleService: TradingRuleService, private readonly assetService: AssetService, @@ -218,6 +220,13 @@ export class LogJobService { Array.from(customAssetMap.entries()).map(async ([b, a]) => { try { const client = this.blockchainRegistryService.getClient(b); + if (!client) { + if (!this.unavailableClientWarningsLogged.has(b)) { + this.logger.warn(`Blockchain client not configured for ${b} - skipping custom balances`); + this.unavailableClientWarningsLogged.add(b); + } + return { blockchain: b, balances: [] }; + } const balances = await this.getCustomBalances(client, a, Config.financialLog.customAddresses).then((b) => b.flat(), diff --git a/src/subdomains/supporting/payin/strategies/register/impl/bitcoin.strategy.ts b/src/subdomains/supporting/payin/strategies/register/impl/bitcoin.strategy.ts index c2325cd46b..1413f3956f 100644 --- a/src/subdomains/supporting/payin/strategies/register/impl/bitcoin.strategy.ts +++ b/src/subdomains/supporting/payin/strategies/register/impl/bitcoin.strategy.ts @@ -20,6 +20,8 @@ export class BitcoinStrategy extends PollingStrategy { @Inject() private readonly depositService: DepositService; + private unavailableWarningLogged = false; + constructor(private readonly payInBitcoinService: PayInBitcoinService) { super(); } @@ -32,7 +34,10 @@ export class BitcoinStrategy extends PollingStrategy { @DfxCron(CronExpression.EVERY_SECOND, { process: Process.PAY_IN, timeout: 7200 }) async checkPayInEntries(): Promise { if (!this.payInBitcoinService.isAvailable()) { - this.logger.warn('Bitcoin node not configured - skipping checkPayInEntries'); + if (!this.unavailableWarningLogged) { + this.logger.warn('Bitcoin node not configured - skipping checkPayInEntries'); + this.unavailableWarningLogged = true; + } return; } diff --git a/src/subdomains/supporting/payment/services/transaction-helper.ts b/src/subdomains/supporting/payment/services/transaction-helper.ts index 752d35241e..c40467e64a 100644 --- a/src/subdomains/supporting/payment/services/transaction-helper.ts +++ b/src/subdomains/supporting/payment/services/transaction-helper.ts @@ -57,6 +57,7 @@ export class TransactionHelper implements OnModuleInit { private readonly addressBalanceCache = new AsyncCache(CacheItemResetPeriod.EVERY_HOUR); private readonly user30dVolumeCache = new AsyncCache(CacheItemResetPeriod.EVERY_HOUR); + private readonly unavailableClientWarningsLogged = new Set(); private transactionSpecifications: TransactionSpecification[]; @@ -606,6 +607,14 @@ export class TransactionHelper implements OnModuleInit { try { const client = this.blockchainRegistryService.getClient(to.blockchain); + if (!client) { + if (!this.unavailableClientWarningsLogged.has(to.blockchain)) { + this.logger.warn(`Blockchain client not configured for ${to.blockchain} - skipping network start fee`); + this.unavailableClientWarningsLogged.add(to.blockchain); + } + return 0; + } + const userBalance = await this.addressBalanceCache.get(`${user.address}-${to.blockchain}`, () => client.getNativeCoinBalanceForAddress(user.address), );