Skip to content

Commit 400b0d5

Browse files
authored
refactor: payment network factory (#930)
1 parent 8180cd2 commit 400b0d5

File tree

15 files changed

+205
-351
lines changed

15 files changed

+205
-351
lines changed

packages/data-access/src/data-access.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ const emptyChannelsWithTopics: DataAccessTypes.IReturnGetChannelsByTopic = {
5757
*/
5858
export default class DataAccess implements DataAccessTypes.IDataAccess {
5959
// Transaction index, that allows storing and retrieving transactions by channel or topic, with time boundaries.
60-
// public for test purpose
61-
public transactionIndex: DataAccessTypes.ITransactionIndex;
60+
private transactionIndex: DataAccessTypes.ITransactionIndex;
6261

6362
// boolean to store the initialization state
6463
protected isInitialized = false;

packages/data-access/test/data-access.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { DataAccessTypes, StorageTypes } from '@requestnetwork/types';
44

55
import RequestDataAccessBlock from '../src/block';
66
import DataAccess from '../src/data-access';
7+
import TransactionIndex from '../src/transaction-index';
78

89
// We use this function to flush the call stack
910
// If we don't use this function, the fake timer will be increased before the interval function being called
@@ -637,10 +638,10 @@ describe('data-access', () => {
637638
readMany: jest.fn(),
638639
};
639640

640-
const dataAccess = new DataAccess(fakeStorageWithNotJsonData);
641+
const transactionIndex = new TransactionIndex();
642+
const dataAccess = new DataAccess(fakeStorageWithNotJsonData, { transactionIndex });
643+
const spy = jest.spyOn(transactionIndex, 'addTransaction').mockImplementation();
641644
await dataAccess.initialize();
642-
const spy = jest.fn();
643-
dataAccess.transactionIndex.addTransaction = spy;
644645
await dataAccess.synchronizeNewDataIds();
645646

646647
expect(spy).not.toHaveBeenCalled();

packages/integration-test/test/node-client.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ describe('Request client using a request node', () => {
415415

416416
await fetchedRequest.refresh();
417417
expect(fetchedRequest.getData().expectedAmount).toBe('0');
418-
});
418+
}, 60000);
419419

420420
it('create an encrypted and unencrypted request with the same content', async () => {
421421
const requestNetwork = new RequestNetwork({

packages/integration-test/test/scheduled/btc-test-data.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export const requestData = {
4040
currency: {
4141
type: RequestLogicTypes.CURRENCY.BTC,
4242
value: 'BTC',
43+
network: 'mainnet',
4344
},
4445
expectedAmount: '100000000000',
4546
payee: payee.identity,

packages/integration-test/test/scheduled/escrow-detector.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Erc20PaymentNetwork } from '../../../payment-detection/dist';
1+
import { Erc20PaymentNetwork } from '@requestnetwork/payment-detection';
22
import { CurrencyManager } from '@requestnetwork/currency';
33
import { createMockErc20FeeRequest } from '../utils';
44
import { mockAdvancedLogic } from './mocks';

packages/integration-test/test/native-token.test.ts renamed to packages/integration-test/test/scheduled/native-token.test.ts

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,41 @@ import { PaymentTypes, RequestLogicTypes } from '@requestnetwork/types';
33
import { PnReferenceBased } from '@requestnetwork/types/dist/extension-types';
44
import { AdvancedLogic } from '@requestnetwork/advanced-logic';
55
import { CurrencyManager } from '@requestnetwork/currency';
6+
import { omit } from 'lodash';
67

78
const advancedLogic = new AdvancedLogic();
8-
const currency = {
9-
network: 'aurora-testnet',
10-
type: RequestLogicTypes.CURRENCY.ETH,
11-
value: 'NEAR',
12-
};
9+
1310
const createCreationActionParams: PnReferenceBased.ICreationParameters = {
1411
paymentAddress: 'payment.testnet',
1512
salt: 'a1a2a3a4a5a6a7a8',
1613
paymentNetworkName: 'aurora-testnet',
1714
};
1815

1916
describe('PaymentNetworkFactory and createExtensionsDataForCreation', () => {
17+
const paymentNetworkFactory = new PaymentNetworkFactory(
18+
advancedLogic,
19+
CurrencyManager.getDefault(),
20+
);
2021
it('PaymentNetworkFactory can createPaymentNetwork (mainnet)', async () => {
21-
const paymentNetwork = PaymentNetworkFactory.createPaymentNetwork({
22-
advancedLogic,
23-
currency: { ...currency, network: 'aurora-testnet' },
24-
paymentNetworkCreationParameters: {
25-
id: PaymentTypes.PAYMENT_NETWORK_ID.NATIVE_TOKEN,
26-
parameters: createCreationActionParams,
27-
},
28-
currencyManager: CurrencyManager.getDefault(),
29-
});
22+
const paymentNetwork = paymentNetworkFactory.createPaymentNetwork(
23+
PaymentTypes.PAYMENT_NETWORK_ID.NATIVE_TOKEN,
24+
RequestLogicTypes.CURRENCY.ETH,
25+
'aurora-testnet',
26+
);
3027
const action = await paymentNetwork.createExtensionsDataForCreation(createCreationActionParams);
3128
expect(action.parameters.paymentAddress).toEqual('payment.testnet');
3229
expect(action.parameters.paymentNetworkName).toEqual('aurora-testnet');
3330
});
3431
it('throws without a payment network name', async () => {
35-
const paymentNetwork = PaymentNetworkFactory.createPaymentNetwork({
36-
advancedLogic,
37-
currency: { ...currency, network: 'aurora-testnet' },
38-
paymentNetworkCreationParameters: {
39-
id: PaymentTypes.PAYMENT_NETWORK_ID.NATIVE_TOKEN,
40-
parameters: { ...createCreationActionParams, paymentNetworkName: undefined },
41-
},
42-
currencyManager: CurrencyManager.getDefault(),
43-
});
32+
const paymentNetwork = paymentNetworkFactory.createPaymentNetwork(
33+
PaymentTypes.PAYMENT_NETWORK_ID.NATIVE_TOKEN,
34+
RequestLogicTypes.CURRENCY.ETH,
35+
'aurora-testnet',
36+
);
4437
await expect(async () => {
45-
await paymentNetwork.createExtensionsDataForCreation(createCreationActionParams);
38+
await paymentNetwork.createExtensionsDataForCreation(
39+
omit(createCreationActionParams, 'paymentNetworkName'),
40+
);
4641
}).rejects.toThrowError(
4742
'The network name is mandatory for the creation of the extension pn-native-token.',
4843
);

packages/payment-detection/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import PaymentNetworkFactory from './payment-network-factory';
1+
import { PaymentNetworkFactory, PaymentNetworkOptions } from './payment-network-factory';
22
import PaymentReferenceCalculator from './payment-reference-calculator';
33

44
import * as BtcPaymentNetwork from './btc';
@@ -26,6 +26,7 @@ export type { TheGraphClient } from './thegraph';
2626

2727
export {
2828
PaymentNetworkFactory,
29+
PaymentNetworkOptions,
2930
PaymentReferenceCalculator,
3031
BtcPaymentNetwork,
3132
DeclarativePaymentDetector,
Lines changed: 53 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
AdvancedLogicTypes,
3-
ExtensionTypes,
4-
PaymentTypes,
5-
RequestLogicTypes,
6-
} from '@requestnetwork/types';
1+
import { AdvancedLogicTypes, PaymentTypes, RequestLogicTypes } from '@requestnetwork/types';
72
import { ICurrencyManager } from '@requestnetwork/currency';
83
import { IPaymentNetworkModuleByType, ISupportedPaymentNetworkByCurrency } from './types';
94
import { BtcMainnetAddressBasedDetector } from './btc/mainnet-address-based';
@@ -18,6 +13,7 @@ import { EthFeeProxyPaymentDetector } from './eth/fee-proxy-detector';
1813
import { AnyToERC20PaymentDetector } from './any/any-to-erc20-proxy';
1914
import { NearConversionNativeTokenPaymentDetector, NearNativeTokenPaymentDetector } from './near';
2015
import { AnyToEthFeeProxyPaymentDetector } from './any/any-to-eth-proxy';
16+
import { getPaymentNetworkExtension } from './utils';
2117

2218
const PN_ID = PaymentTypes.PAYMENT_NETWORK_ID;
2319

@@ -62,133 +58,84 @@ const anyCurrencyPaymentNetwork: IPaymentNetworkModuleByType = {
6258
[PN_ID.ANY_TO_NATIVE]: NearConversionNativeTokenPaymentDetector,
6359
};
6460

61+
export type PaymentNetworkOptions = {
62+
/** override default bitcoin detection provider */
63+
bitcoinDetectionProvider?: PaymentTypes.IBitcoinDetectionProvider;
64+
/** the explorer API (eg Etherscan) api keys, for PNs that rely on it. Record by network name */
65+
explorerApiKeys?: Record<string, string>;
66+
};
67+
6568
/** Factory to create the payment network according to the currency and payment network type */
66-
export default class PaymentNetworkFactory {
69+
export class PaymentNetworkFactory {
70+
/**
71+
*
72+
* @param advancedLogic the advanced-logic layer in charge of the extensions
73+
* @param currencyManager the currency manager handling supported currencies
74+
* @param options the payment network options
75+
*/
76+
constructor(
77+
private readonly advancedLogic: AdvancedLogicTypes.IAdvancedLogic,
78+
private readonly currencyManager: ICurrencyManager,
79+
private readonly options?: PaymentNetworkOptions,
80+
) {}
81+
6782
/**
6883
* Creates a payment network according to payment network creation parameters
6984
* It throws if the payment network given is not supported by this library
7085
*
71-
* @param advancedLogic the advanced-logic layer in charge of the extensions
7286
* @param currency the currency of the request
7387
* @param paymentNetworkCreationParameters creation parameters of payment network
74-
* @param bitcoinDetectionProvider bitcoin detection provider
75-
* @param currencyManager the currency manager handling supported currencies
7688
* @returns the module to handle the payment network
7789
*/
78-
public static createPaymentNetwork({
79-
advancedLogic,
80-
currency,
81-
paymentNetworkCreationParameters,
82-
bitcoinDetectionProvider,
83-
currencyManager,
84-
}: {
85-
advancedLogic: AdvancedLogicTypes.IAdvancedLogic;
86-
currency: RequestLogicTypes.ICurrency;
87-
paymentNetworkCreationParameters: PaymentTypes.IPaymentNetworkCreateParameters;
88-
bitcoinDetectionProvider?: PaymentTypes.IBitcoinDetectionProvider;
89-
currencyManager: ICurrencyManager;
90-
}): PaymentTypes.IPaymentNetwork {
91-
const paymentNetworkForCurrency = this.supportedPaymentNetworksForCurrency(currency);
90+
public createPaymentNetwork(
91+
paymentNetworkId: PaymentTypes.PAYMENT_NETWORK_ID,
92+
currencyType: RequestLogicTypes.CURRENCY,
93+
currencyNetwork?: string,
94+
): PaymentTypes.IPaymentNetwork {
95+
const currencyPaymentMap =
96+
supportedPaymentNetwork[currencyType]?.[currencyNetwork || 'mainnet'] ||
97+
supportedPaymentNetwork[currencyType]?.['*'] ||
98+
{};
99+
const paymentNetworkMap = {
100+
...currencyPaymentMap,
101+
...anyCurrencyPaymentNetwork,
102+
};
92103

93-
if (!paymentNetworkForCurrency[paymentNetworkCreationParameters.id]) {
104+
if (!paymentNetworkMap[paymentNetworkId]) {
94105
throw new Error(
95-
`the payment network id: ${
96-
paymentNetworkCreationParameters.id
97-
} is not supported for the currency: ${currency.type} on network ${
98-
currency.network || 'mainnet'
106+
`the payment network id: ${paymentNetworkId} is not supported for the currency: ${currencyType} on network ${
107+
currencyNetwork || 'mainnet'
99108
}`,
100109
);
101110
}
102-
103-
return new paymentNetworkForCurrency[paymentNetworkCreationParameters.id]({
104-
advancedLogic,
105-
bitcoinDetectionProvider,
106-
currencyManager,
111+
return new paymentNetworkMap[paymentNetworkId]({
112+
advancedLogic: this.advancedLogic,
113+
currencyManager: this.currencyManager,
114+
...this.options,
107115
});
108116
}
109117

110118
/**
111119
* Gets the module to the payment network of a request
112120
* It throws if the payment network found is not supported by this library
113121
*
114-
* @param advancedLogic the advanced-logic layer in charge of the extensions
115122
* @param request the request
116-
* @param bitcoinDetectionProvider bitcoin detection provider
117-
* @param explorerApiKeys the explorer API (eg Etherscan) api keys, for PNs that rely on it. Record by network name.
118-
* @param currencyManager the currency manager handling supported currencies
119123
* @returns the module to handle the payment network or null if no payment network found
120124
*/
121-
public static getPaymentNetworkFromRequest({
122-
advancedLogic,
123-
request,
124-
bitcoinDetectionProvider,
125-
explorerApiKeys,
126-
currencyManager,
127-
}: {
128-
advancedLogic: AdvancedLogicTypes.IAdvancedLogic;
129-
request: RequestLogicTypes.IRequest;
130-
currencyManager: ICurrencyManager;
131-
bitcoinDetectionProvider?: PaymentTypes.IBitcoinDetectionProvider;
132-
explorerApiKeys?: Record<string, string>;
133-
}): PaymentTypes.IPaymentNetwork | null {
134-
const currency = request.currency;
135-
const extensionPaymentNetwork = Object.values(request.extensions || {}).find(
136-
(extension) => extension.type === ExtensionTypes.TYPE.PAYMENT_NETWORK,
137-
);
125+
public getPaymentNetworkFromRequest(
126+
request: RequestLogicTypes.IRequest,
127+
): PaymentTypes.IPaymentNetwork | null {
128+
const pn = getPaymentNetworkExtension(request);
138129

139-
if (!extensionPaymentNetwork) {
130+
if (!pn) {
140131
return null;
141132
}
142133

143-
const paymentNetworkId = extensionPaymentNetwork.id;
144-
const paymentNetworkForCurrency = this.supportedPaymentNetworksForCurrency(currency);
145-
146-
if (!paymentNetworkForCurrency[paymentNetworkId]) {
147-
throw new Error(
148-
`the payment network id: ${paymentNetworkId} is not supported for the currency: ${
149-
currency.type
150-
} on network ${currency.network || 'mainnet'}`,
151-
);
152-
}
153-
154-
return new paymentNetworkForCurrency[paymentNetworkId]({
155-
advancedLogic,
156-
bitcoinDetectionProvider,
157-
explorerApiKeys,
158-
currencyManager,
159-
});
160-
}
161-
162-
/**
163-
* Gets the payment networks supported for a Currency object
164-
*
165-
* @param currency The currency to get the supported networks for
166-
*/
167-
public static supportedPaymentNetworksForCurrency(
168-
currency: RequestLogicTypes.ICurrency,
169-
): IPaymentNetworkModuleByType {
170-
if (!supportedPaymentNetwork[currency.type]) {
171-
return anyCurrencyPaymentNetwork;
172-
}
173-
174-
const paymentNetwork =
175-
supportedPaymentNetwork[currency.type][currency.network || 'mainnet'] ||
176-
supportedPaymentNetwork[currency.type]['*'];
177-
178-
return { ...paymentNetwork, ...anyCurrencyPaymentNetwork };
179-
}
180-
181-
/**
182-
* Checks if a networkId is part of the supported networks for given currency
183-
*
184-
* @param paymentNetworkId The networkId to check is supported by this currency
185-
* @param currency The currency to check the supported networks for
186-
*/
187-
public static currencySupportsPaymentNetwork(
188-
paymentNetworkId: PaymentTypes.PAYMENT_NETWORK_ID,
189-
currency: RequestLogicTypes.ICurrency,
190-
): boolean {
191-
const paymentNetworks = this.supportedPaymentNetworksForCurrency(currency);
192-
return !!paymentNetworks[paymentNetworkId];
134+
const paymentNetworkId = pn.id as unknown as PaymentTypes.PAYMENT_NETWORK_ID;
135+
return this.createPaymentNetwork(
136+
paymentNetworkId,
137+
request.currency.type,
138+
request.currency.network,
139+
);
193140
}
194141
}

packages/payment-detection/test/near/near-native-conversion.test.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
RequestLogicTypes,
66
} from '@requestnetwork/types';
77
import { CurrencyDefinition, CurrencyManager } from '@requestnetwork/currency';
8-
import PaymentNetworkFactory from '../../src/payment-network-factory';
8+
import { PaymentNetworkFactory } from '../../src/payment-network-factory';
99
import PaymentReferenceCalculator from '../../src/payment-reference-calculator';
1010
import {
1111
NearConversionNativeTokenPaymentDetector,
@@ -75,6 +75,7 @@ const graphPaymentEvent = {
7575
gasPrice: '2425000017',
7676
};
7777

78+
const paymentNetworkFactory = new PaymentNetworkFactory(mockAdvancedLogic, currencyManager);
7879
describe('Near payments detection', () => {
7980
beforeAll(() => {
8081
graphql.request.mockResolvedValue({
@@ -121,21 +122,16 @@ describe('Near payments detection', () => {
121122
});
122123

123124
it('PaymentNetworkFactory can get the detector (testnet)', async () => {
124-
expect(
125-
PaymentNetworkFactory.getPaymentNetworkFromRequest({
126-
advancedLogic: mockAdvancedLogic,
127-
request,
128-
currencyManager,
129-
}),
130-
).toBeInstanceOf(NearConversionNativeTokenPaymentDetector);
125+
expect(paymentNetworkFactory.getPaymentNetworkFromRequest(request)).toBeInstanceOf(
126+
NearConversionNativeTokenPaymentDetector,
127+
);
131128
});
132129

133130
it('PaymentNetworkFactory can get the detector (mainnet)', async () => {
134131
expect(
135-
PaymentNetworkFactory.getPaymentNetworkFromRequest({
136-
advancedLogic: mockAdvancedLogic,
137-
request: { ...request, currency: { ...request.currency, network: 'aurora' } },
138-
currencyManager,
132+
paymentNetworkFactory.getPaymentNetworkFromRequest({
133+
...request,
134+
currency: { ...request.currency, network: 'aurora' },
139135
}),
140136
).toBeInstanceOf(NearConversionNativeTokenPaymentDetector);
141137
});

0 commit comments

Comments
 (0)