Skip to content

Commit

Permalink
feat: escrow detector class (#773)
Browse files Browse the repository at this point in the history
  • Loading branch information
KolevDarko committed Mar 10, 2022
1 parent feeb7d0 commit c4c2276
Show file tree
Hide file tree
Showing 31 changed files with 1,080 additions and 378 deletions.
62 changes: 14 additions & 48 deletions packages/integration-test/test/scheduled/erc20-fee-proxy.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { Erc20PaymentNetwork } from '@requestnetwork/payment-detection';
import {
ExtensionTypes,
IdentityTypes,
PaymentTypes,
RequestLogicTypes,
} from '@requestnetwork/types';
import { PaymentTypes, RequestLogicTypes } from '@requestnetwork/types';
import { CurrencyManager } from '@requestnetwork/currency';

import { mockAdvancedLogic } from './mocks';
Expand All @@ -17,57 +12,24 @@ import {
privateErc20Address,
requestNetwork,
} from './fixtures';

const createMockRequest = ({
network,
tokenAddress,
paymentAddress,
salt,
requestId,
}: Record<
'network' | 'tokenAddress' | 'paymentAddress' | 'salt' | 'requestId',
string
>): RequestLogicTypes.IRequest => ({
creator: { type: IdentityTypes.TYPE.ETHEREUM_ADDRESS, value: '0x2' },
currency: {
network,
type: RequestLogicTypes.CURRENCY.ERC20,
value: tokenAddress,
},
events: [],
expectedAmount: '0',
extensions: {
[ExtensionTypes.ID.PAYMENT_NETWORK_ERC20_FEE_PROXY_CONTRACT]: {
events: [],
id: ExtensionTypes.ID.PAYMENT_NETWORK_ERC20_FEE_PROXY_CONTRACT,
type: ExtensionTypes.TYPE.PAYMENT_NETWORK,
values: {
paymentAddress,
salt,
},
version: '0.1.0',
},
},
extensionsData: [],
requestId,
state: RequestLogicTypes.STATE.CREATED,
timestamp: 0,
version: '0.2',
});
import { createMockErc20FeeRequest } from '../utils';

const erc20FeeProxy = new Erc20PaymentNetwork.ERC20FeeProxyPaymentDetector({
// FIXME: the mocked advanced logic is address based
advancedLogic: mockAdvancedLogic,
currencyManager: CurrencyManager.getDefault(),
});

describe('ERC20 Fee Proxy detection test-suite', () => {
it('can getBalance on a mainnet request', async () => {
const mockRequest = createMockRequest({
const mockRequest = createMockErc20FeeRequest({
network: 'mainnet',
requestId: '016d4cf8006982f7d91a437f8c72700aa62767de00a605133ee5f84ad8d224ba04',
paymentAddress: '0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93',
salt: '8097784e131ee627',
tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
feeAddress: '0x35d0e078755cd84d3e0656caab417dee1d7939c7',
feeAmount: '10',
});

const balance = await erc20FeeProxy.getBalance(mockRequest);
Expand All @@ -82,12 +44,14 @@ describe('ERC20 Fee Proxy detection test-suite', () => {
});

it('can getBalance on a rinkeby request', async () => {
const mockRequest = createMockRequest({
const mockRequest = createMockErc20FeeRequest({
network: 'rinkeby',
requestId: '0188791633ff0ec72a7dbdefb886d2db6cccfa98287320839c2f173c7a4e3ce7e1',
paymentAddress: '0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93',
salt: '0ee84db293a752c6',
tokenAddress: '0xFab46E002BbF0b4509813474841E0716E6730136', // FAU
feeAddress: '0x35d0e078755cd84d3e0656caab417dee1d7939c7',
feeAmount: '1000000000000000',
});

const balance = await erc20FeeProxy.getBalance(mockRequest);
Expand All @@ -96,18 +60,20 @@ describe('ERC20 Fee Proxy detection test-suite', () => {
expect(balance.events).toHaveLength(1);
expect(balance.events[0].name).toBe('payment');
const params = balance.events[0].parameters as PaymentTypes.IERC20FeePaymentEventParameters;
expect(params).toBe('0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93');
expect(params?.to).toBe('0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93');
expect(balance.events[0].amount).toBe('1000000000000000000000');
expect(balance.events[0].timestamp).toBe(1599013969);
});

it('can getBalance on a matic request, with TheGraph', async () => {
const mockRequest = createMockRequest({
const mockRequest = createMockErc20FeeRequest({
network: 'matic',
requestId: '014bcd076791fb915af457df1d3f26c81ff66f7e278e4a18f0e48a1705572a6306',
paymentAddress: '0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93',
salt: '8c5ea6f8b4a14fe0',
tokenAddress: '0x282d8efce846a88b159800bd4130ad77443fa1a1', // FAU
feeAddress: '0x35d0e078755cd84d3e0656caab417dee1d7939c7',
feeAmount: '1000000000000000',
});

const balance = await erc20FeeProxy.getBalance(mockRequest);
Expand All @@ -116,7 +82,7 @@ describe('ERC20 Fee Proxy detection test-suite', () => {
expect(balance.events).toHaveLength(1);
expect(balance.events[0].name).toBe('payment');
const params = balance.events[0].parameters as PaymentTypes.IERC20FeePaymentEventParameters;
expect(params).toBe('0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93');
expect(params.to).toBe('0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93');
expect(balance.events[0].amount).toBe('1000000000000000000');
expect(balance.events[0].timestamp).toBe(1621953168);
}, 15000);
Expand Down
46 changes: 46 additions & 0 deletions packages/integration-test/test/scheduled/escrow-detector.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Erc20PaymentNetwork } from '../../../payment-detection/dist';
import { CurrencyManager } from '@requestnetwork/currency';
import { createMockErc20FeeRequest } from '../utils';
import { mockAdvancedLogic } from './mocks';

const feeProxyDetector = new Erc20PaymentNetwork.ERC20FeeProxyPaymentDetector({
advancedLogic: mockAdvancedLogic,
currencyManager: CurrencyManager.getDefault(),
});

describe('ERC20 with Escrow detection test-suite', () => {
it('can getBalance on a matic request, with TheGraph', async () => {
const mockRequest = createMockErc20FeeRequest({
network: 'matic',
requestId: '014bcd076791fb915af457df1d3f26c81ff66f7e278e4a18f0e48a1705572a6306',
paymentAddress: '0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93',
salt: '8c5ea6f8b4a14fe0',
tokenAddress: '0x282d8efce846a88b159800bd4130ad77443fa1a1', // FAU
feeAddress: '0x35d0e078755cd84d3e0656caab417dee1d7939c7',
feeAmount: '1000000000000000',
});

const balance = await feeProxyDetector.getBalance(mockRequest);

expect(balance.balance).toBe('1000000000000000000');
}, 15000);

it('can getBalance on a rinkeby request', async () => {
const mockRequest = createMockErc20FeeRequest({
network: 'rinkeby',
requestId: '0188791633ff0ec72a7dbdefb886d2db6cccfa98287320839c2f173c7a4e3ce7e1',
paymentAddress: '0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93',
salt: '0ee84db293a752c6',
tokenAddress: '0xFab46E002BbF0b4509813474841E0716E6730136', // FAU
feeAddress: '0x35d0e078755cd84d3e0656caab417dee1d7939c7',
feeAmount: '1000000000000000',
});

const balance = await feeProxyDetector.getBalance(mockRequest);

// Sanity check
expect(balance.balance).toBe('1000000000000000000');
const paymentEvents = balance.events;
expect(paymentEvents).toHaveLength(3);
});
});
42 changes: 42 additions & 0 deletions packages/integration-test/test/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ExtensionTypes, IdentityTypes, RequestLogicTypes } from '@requestnetwork/types';

export const createMockErc20FeeRequest = ({
network,
tokenAddress,
paymentAddress,
salt,
requestId,
feeAddress,
feeAmount,
}: Record<
'network' | 'tokenAddress' | 'paymentAddress' | 'salt' | 'requestId' | 'feeAddress' | 'feeAmount',
string
>): RequestLogicTypes.IRequest => ({
creator: { type: IdentityTypes.TYPE.ETHEREUM_ADDRESS, value: '0x2' },
currency: {
network,
type: RequestLogicTypes.CURRENCY.ERC20,
value: tokenAddress,
},
events: [],
expectedAmount: '0',
extensions: {
[ExtensionTypes.ID.PAYMENT_NETWORK_ERC20_FEE_PROXY_CONTRACT]: {
events: [],
id: ExtensionTypes.ID.PAYMENT_NETWORK_ERC20_FEE_PROXY_CONTRACT,
type: ExtensionTypes.TYPE.PAYMENT_NETWORK,
values: {
paymentAddress,
salt,
feeAddress,
feeAmount,
},
version: '0.1.0',
},
},
extensionsData: [],
requestId,
state: RequestLogicTypes.STATE.CREATED,
timestamp: 0,
version: '0.2.0',
});
13 changes: 8 additions & 5 deletions packages/payment-detection/src/any/any-to-erc20-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ export class AnyToERC20PaymentDetector extends ERC20FeeProxyPaymentDetectorBase<
requestCurrency: RequestLogicTypes.ICurrency,
paymentChain: string,
paymentNetwork: ExtensionTypes.IState<ExtensionTypes.PnAnyToErc20.ICreationParameters>,
): Promise<PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IERC20FeePaymentEventParameters>[]> {
): Promise<PaymentTypes.AllNetworkEvents<PaymentTypes.IERC20FeePaymentEventParameters>> {
if (!address) {
return [];
return {
paymentEvents: [],
};
}
const { acceptedTokens, maxRateTimespan = 0 } = paymentNetwork.values;

Expand Down Expand Up @@ -125,9 +127,10 @@ export class AnyToERC20PaymentDetector extends ERC20FeeProxyPaymentDetectorBase<
maxRateTimespan,
);

return infoRetriever.getTransferEvents() as Promise<
PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IERC20FeePaymentEventParameters>[]
>;
const paymentEvents = (await infoRetriever.getTransferEvents()) as PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IERC20FeePaymentEventParameters>[];
return {
paymentEvents,
};
}

protected getPaymentChain(request: RequestLogicTypes.IRequest): string {
Expand Down
62 changes: 34 additions & 28 deletions packages/payment-detection/src/any/any-to-eth-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,46 +69,52 @@ export class AnyToEthFeeProxyPaymentDetector extends AnyToAnyDetector<
requestCurrency: RequestLogicTypes.ICurrency,
paymentChain: string,
paymentNetwork: ExtensionTypes.IState<ExtensionTypes.PnAnyToEth.ICreationParameters>,
): Promise<PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IETHPaymentEventParameters>[]> {
): Promise<PaymentTypes.AllNetworkEvents<PaymentTypes.IETHPaymentEventParameters>> {
if (!address) {
return [];
return {
paymentEvents: [],
};
}

const contractInfo = AnyToEthFeeProxyPaymentDetector.getDeploymentInformation(
paymentChain,
paymentNetwork.version,
);

const abi = SmartContracts.ethConversionArtifact.getContractAbi(contractInfo.contractVersion);

const currency = this.currencyManager.fromStorageCurrency(requestCurrency);
if (!currency) {
throw new UnsupportedCurrencyError(requestCurrency.value);
} else {
const proxyInfoRetriever = this.useTheGraph(paymentChain)
? new TheGraphConversionRetriever(
currency,
paymentReference,
contractInfo.address,
address,
eventName,
paymentChain,
undefined,
paymentNetwork.values?.maxRateTimespan,
)
: new AnyToEthInfoRetriever(
currency,
paymentReference,
contractInfo.address,
contractInfo.creationBlockNumber,
abi,
address,
eventName,
paymentChain,
undefined,
paymentNetwork.values?.maxRateTimespan,
);
const paymentEvents = await proxyInfoRetriever.getTransferEvents();
return {
paymentEvents,
};
}

const proxyInfoRetriever = this.useTheGraph(paymentChain)
? new TheGraphConversionRetriever(
currency,
paymentReference,
contractInfo.address,
address,
eventName,
paymentChain,
undefined,
paymentNetwork.values?.maxRateTimespan,
)
: new AnyToEthInfoRetriever(
currency,
paymentReference,
contractInfo.address,
contractInfo.creationBlockNumber,
abi,
address,
eventName,
paymentChain,
undefined,
paymentNetwork.values?.maxRateTimespan,
);

return await proxyInfoRetriever.getTransferEvents();
}

/**
Expand Down
7 changes: 5 additions & 2 deletions packages/payment-detection/src/btc/address-based.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export abstract class BtcAddressBasedDetector extends PaymentDetectorBase<
*/
protected async getEvents(
request: RequestLogicTypes.IRequest,
): Promise<PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IBTCPaymentEventParameters>[]> {
): Promise<PaymentTypes.AllNetworkEvents<PaymentTypes.IBTCPaymentEventParameters>> {
const { paymentAddress, refundAddress } = this.getPaymentExtension(request).values;

this.checkRequiredParameter(paymentAddress, 'paymentAddress');
Expand All @@ -93,6 +93,9 @@ export abstract class BtcAddressBasedDetector extends PaymentDetectorBase<
)
: { events: [] },
]);
return [...payments.events, ...refunds.events];
const paymentEvents = [...payments.events, ...refunds.events];
return {
paymentEvents,
};
}
}
6 changes: 4 additions & 2 deletions packages/payment-detection/src/declarative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ export class DeclarativePaymentDetector extends DeclarativePaymentDetectorBase<

protected async getEvents(
request: RequestLogicTypes.IRequest,
): Promise<PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IDeclarativePaymentEventParameters>[]> {
return this.getDeclarativeEvents(request);
): Promise<PaymentTypes.AllNetworkEvents<PaymentTypes.IDeclarativePaymentEventParameters>> {
return {
paymentEvents: this.getDeclarativeEvents(request),
};
}
}
7 changes: 5 additions & 2 deletions packages/payment-detection/src/erc20/address-based.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class ERC20AddressBasedPaymentDetector extends PaymentDetectorBase<
*/
protected async getEvents(
request: RequestLogicTypes.IRequest,
): Promise<PaymentTypes.IPaymentNetworkEvent<PaymentTypes.IERC20PaymentEventParameters>[]> {
): Promise<PaymentTypes.AllNetworkEvents<PaymentTypes.IERC20PaymentEventParameters>> {
if (!request.currency.network) {
request.currency.network = 'mainnet';
}
Expand Down Expand Up @@ -110,7 +110,10 @@ export class ERC20AddressBasedPaymentDetector extends PaymentDetectorBase<
request.currency.value,
);

return [...paymentEvents, ...refundEvents];
const allPaymentEvents = [...paymentEvents, ...refundEvents];
return {
paymentEvents: allPaymentEvents,
};
}

/**
Expand Down

0 comments on commit c4c2276

Please sign in to comment.