refactor xmr rate module to exchange rate module for multi crypto support

This commit is contained in:
2026-09-02 14:53:50 +02:00
parent 6818f08dbe
commit 0510695598
29 changed files with 630 additions and 388 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MoneroWalletModule } from '../moneroWallet/MoneroWalletModule';
import { XmrRateModule } from '../xmrRate/XmrRateModule';
import { ExchangeRateModule } from '../exchangeRate/ExchangeRateModule';
import { Invoice } from './entities/Invoice';
import { InvoiceMoneroDetails } from './entities/InvoiceMoneroDetails';
import { InvoicePayment } from './entities/InvoicePayment';
@@ -12,7 +12,7 @@ import { InvoiceService } from './services/InvoiceService';
imports: [
TypeOrmModule.forFeature([Invoice, InvoicePayment, InvoiceMoneroDetails]),
MoneroWalletModule,
XmrRateModule
ExchangeRateModule
],
providers: [InvoicePaymentService, InvoiceService],
exports: [InvoiceService, TypeOrmModule.forFeature([Invoice])]
@@ -2,7 +2,7 @@ import { Logger, ServiceUnavailableException } from '@nestjs/common';
import type { ConfigService } from '@nestjs/config';
import type { Repository } from 'typeorm';
import type { MoneroWalletRpcClient } from '../../moneroWallet/services/MoneroWalletRpcClient';
import type { XmrRateService } from '../../xmrRate/services/XmrRateService';
import type { ExchangeRateService } from '../../exchangeRate/services/ExchangeRateService';
import { Invoice } from '../entities/Invoice';
import { InvoiceReason } from '../types/InvoiceReason';
import { PaymentMethod } from '../types/PaymentMethod';
@@ -22,8 +22,8 @@ describe('InvoiceService', () => {
let walletRpcClient: {
createAddress: jest.Mock;
};
let xmrRateService: {
getLiveFiatPerXmr: jest.Mock;
let exchangeRateService: {
getLiveFiatPerCrypto: jest.Mock;
};
let errorLogSpy: jest.SpiedFunction<typeof Logger.prototype.error>;
@@ -60,15 +60,15 @@ describe('InvoiceService', () => {
})
};
xmrRateService = {
getLiveFiatPerXmr: jest.fn().mockReturnValue(150)
exchangeRateService = {
getLiveFiatPerCrypto: jest.fn().mockReturnValue(150)
};
service = new InvoiceService(
invoiceRepo as unknown as Repository<Invoice>,
configService as unknown as ConfigService,
walletRpcClient as unknown as MoneroWalletRpcClient,
xmrRateService as unknown as XmrRateService
exchangeRateService as unknown as ExchangeRateService
);
});
@@ -85,7 +85,7 @@ describe('InvoiceService', () => {
});
it('throws when the live XMR rate is unavailable for checkout invoices', async () => {
xmrRateService.getLiveFiatPerXmr.mockReturnValue(null);
exchangeRateService.getLiveFiatPerCrypto.mockReturnValue(null);
await expect(issueCheckoutInvoice()).rejects.toThrow(
new ServiceUnavailableException("We can't show a price right now. Please try again in a few minutes.")
@@ -169,7 +169,7 @@ describe('InvoiceService', () => {
});
it('uses shipping-specific messages and address labels for shipping invoices', async () => {
xmrRateService.getLiveFiatPerXmr.mockReturnValue(null);
exchangeRateService.getLiveFiatPerCrypto.mockReturnValue(null);
await expect(
service.issueInvoice({
@@ -184,7 +184,7 @@ describe('InvoiceService', () => {
)
);
xmrRateService.getLiveFiatPerXmr.mockReturnValue(150);
exchangeRateService.getLiveFiatPerCrypto.mockReturnValue(150);
walletRpcClient.createAddress.mockRejectedValue(new Error('rpc down'));
await expect(
@@ -9,7 +9,7 @@ import { convertFiatToXmr } from '../../../utils/monero/convertFiatToXmr';
import { convertXmrToXmrAtomic } from '../../../utils/monero/convertXmrToXmrAtomic';
import { resolveMinConfirmations } from '../../../utils/monero/resolveMinConfirmations';
import { MoneroWalletRpcClient } from '../../moneroWallet/services/MoneroWalletRpcClient';
import { XmrRateService } from '../../xmrRate/services/XmrRateService';
import { ExchangeRateService } from '../../exchangeRate/services/ExchangeRateService';
import { Invoice } from '../entities/Invoice';
import { InvoiceReason } from '../types/InvoiceReason';
import type { IssueInvoiceData } from '../types/IssueInvoiceData';
@@ -25,10 +25,10 @@ export class InvoiceService {
private readonly invoiceRepo: Repository<Invoice>,
private readonly configService: ConfigService,
private readonly walletRpcClient: MoneroWalletRpcClient,
private readonly xmrRateService: XmrRateService
private readonly exchangeRateService: ExchangeRateService
) {}
async issueInvoice(data: IssueInvoiceData): Promise<Invoice> {
async issueInvoice(data: IssueInvoiceData): Promise<Invoice | undefined> {
switch (data.paymentMethod) {
case PaymentMethod.Xmr:
return this.issueXmrInvoice(data);
@@ -44,7 +44,7 @@ export class InvoiceService {
contextId
);
const fiatPerXmr = this.xmrRateService.getLiveFiatPerXmr();
const fiatPerXmr = this.exchangeRateService.getLiveFiatPerCrypto(PaymentMethod.Xmr);
if (fiatPerXmr === null) {
throw new ServiceUnavailableException(rateUnavailableMessage);
@@ -1,3 +1,4 @@
export enum PaymentMethod {
Xmr = 'xmr'
Xmr = 'xmr',
Btc = 'btc'
}