forked from RequestNetwork/requestNetwork
-
Notifications
You must be signed in to change notification settings - Fork 1
/
payment-detector-base.ts
100 lines (90 loc) · 3.35 KB
/
payment-detector-base.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { BigNumber } from 'ethers';
import { ExtensionTypes, PaymentTypes, RequestLogicTypes } from '@requestnetwork/types';
import {
BalanceError,
ExtensionMissingRequiredValue,
getBalanceErrorObject,
} from './balance-error';
export abstract class PaymentDetectorBase<
TExtension extends ExtensionTypes.IExtension,
TPaymentEventParameters extends PaymentTypes.GenericEventParameters,
> implements PaymentTypes.IPaymentNetwork<TPaymentEventParameters>
{
protected constructor(
public readonly paymentNetworkId: ExtensionTypes.PAYMENT_NETWORK_ID,
public readonly extension: TExtension,
) {}
abstract createExtensionsDataForCreation(
paymentNetworkCreationParameters: PaymentTypes.PaymentNetworkCreateParameters['parameters'],
): Promise<any>;
abstract createExtensionsDataForAddRefundInformation(parameters: any): any;
abstract createExtensionsDataForAddPaymentInformation(parameters: any): any;
/**
* Gets the balance and the payment/refund events
*
* @param request the request to check
* @returns the balance and the payment/refund events
*/
public async getBalance(
request: RequestLogicTypes.IRequest,
): Promise<PaymentTypes.IBalanceWithEvents<TPaymentEventParameters>> {
try {
const allNetworkEvents = await this.getEvents(request);
const rawPaymentEvents = allNetworkEvents.paymentEvents;
const events = this.sortEvents(rawPaymentEvents);
const balance = this.computeBalance(events).toString();
const escrowEvents = this.sortEscrowEvents(allNetworkEvents.escrowEvents || []);
return {
balance,
events,
escrowEvents,
};
} catch (error) {
return getBalanceErrorObject(error);
}
}
/**
* Gets all payment events for a given Request
*/
protected abstract getEvents(
request: RequestLogicTypes.IRequest,
): Promise<PaymentTypes.AllNetworkEvents<TPaymentEventParameters>>;
protected getPaymentExtension(
request: RequestLogicTypes.IRequest,
): TExtension extends ExtensionTypes.IExtension<infer X> ? ExtensionTypes.IState<X> : never {
const extension = request.extensions[this.paymentNetworkId];
if (!extension) {
throw new BalanceError(
`The request does not have the extension: ${this.paymentNetworkId}`,
PaymentTypes.BALANCE_ERROR_CODE.WRONG_EXTENSION,
);
}
return extension as any;
}
protected computeBalance(events: PaymentTypes.IPaymentNetworkEvent<unknown>[]): BigNumber {
return events.reduce(
(sum, curr) =>
curr.name === PaymentTypes.EVENTS_NAMES.PAYMENT
? sum.add(curr.amount)
: curr.name === PaymentTypes.EVENTS_NAMES.REFUND
? sum.sub(curr.amount)
: sum,
BigNumber.from(0),
);
}
protected sortEvents(
events: PaymentTypes.IPaymentNetworkEvent<TPaymentEventParameters>[],
): PaymentTypes.IPaymentNetworkEvent<TPaymentEventParameters>[] {
return events.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
}
protected sortEscrowEvents(
events: PaymentTypes.EscrowNetworkEvent[],
): PaymentTypes.EscrowNetworkEvent[] {
return events.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
}
protected checkRequiredParameter<T>(value: T | undefined, name: string): asserts value is T {
if (!value) {
throw new ExtensionMissingRequiredValue(this.paymentNetworkId, name);
}
}
}