From ca405370f2082f1c4775a08ad07784084169017e Mon Sep 17 00:00:00 2001 From: Yo <56731761+yomarion@users.noreply.github.com> Date: Mon, 31 Jan 2022 20:18:51 +0100 Subject: [PATCH] chore(payment-detection): clean Retrievers type. Document. (#752) - chore(payment-detection): Revamped README - chore(payment-detection): Renamed IPaymentNetworkInfoRetriever > IPaymentRetriever - chore(payment-detection): Renamed IPaymentNetworkBaseInfoRetriever > IEventRetriver - chore: Moved the definition of retrievers from types to payment-detection --- packages/payment-detection/README.md | 67 ++++++-- .../src/any/retrievers/thegraph.ts | 5 +- .../src/erc20/address-based-info-retriever.ts | 3 +- .../src/erc20/escrow-info-retriever.ts | 3 +- .../src/erc20/proxy-info-retriever.ts | 3 +- .../src/eth/info-retriever.ts | 3 +- .../src/eth/proxy-info-retriever.ts | 3 +- .../src/payment-network-factory.ts | 7 +- packages/payment-detection/src/types.ts | 32 ++++ packages/types/src/payment-types.ts | 154 +++++++++--------- 10 files changed, 179 insertions(+), 101 deletions(-) create mode 100644 packages/payment-detection/src/types.ts diff --git a/packages/payment-detection/README.md b/packages/payment-detection/README.md index 98dc6c2268..fb77f7a152 100644 --- a/packages/payment-detection/README.md +++ b/packages/payment-detection/README.md @@ -1,22 +1,65 @@ # @requestnetwork/payment-detection `@requestnetwork/payment-detection` is a typescript library part of the [Request Network protocol](https://github.com/RequestNetwork/requestNetwork). -It contains client-side payment detection for all supported payment networks. +It contains the implementation of request-related events interpretations, typically onchain payments of requests. -### Payment and Refund detections +The interpretation of events is specified by the payment extension added to the request. [Cf. advanced-logic specifications](../advanced-logic/specs/). + +# Balance and events If a payment network has been given to the request, the payment detection can be done. -From the information provided in payment network, the library will feed the property `balance` of the request with: +Based on information found in the payment network state, and included manual payment declarations, the library will perform queries and feed the property `balance` of the request with: + +- `balance`: the detected amount paid on the request, in request currency +- `events`: all the payments, payment declarations, refunds, and other balance-related events with the amount, timestamp etc... + +# Retrievers and detectors + +This library relies on two concepts: + +- **Retrievers** perform RPC or TheGraph calls and fetch relevant events. Balance-impacting events are fetched with `InfoRetrievers`, implementing the `getTransferEvents()` method (cf. [IPaymentRetriever](./src/types.ts)) +- **Payment detectors** implement the interface **PaymentTypes.IPaymentNetwork**, with the method `getBalance()`, which calls retrievers and interpret events according to the payment network (cf. [Abstract PaymentDetectorBase](./src/payment-detector-base.ts)). `getBalance()` returns the balance as well as events: payments, refunds, and possibly other events (declarations, escrow events...) + +## PaymentDetectorBase + +A good part of the logic is implemented in the abstract class `PaymentDetectorBase`: + +```typescript +export abstract class PaymentDetectorBase< + TExtension extends ExtensionTypes.IExtension, + TPaymentEventParameters +> implements PaymentTypes.IPaymentNetwork { + public async getBalance( + request: RequestLogicTypes.IRequest, + ): Promise> { + // ... + + // getEvents() should be implemented by children payment detectors, and use appropriate retrievers + // For example: RPC or The Graph based retriever + const rawEvents = await this.getEvents(request); + // ... + // computeBalance() sums up all payment events and deduces all refunds. + const balance = this.computeBalance(events).toString(); + + return { + balance, + events, + }; + } +} +``` + +[cf. full implementation](./src/payment-detector-base.ts) + +## Subgraph-based payment retrievers + +For TheGraph-based information retrieval, a client can be retrieved using `getTheGraphClient()` in `./src/thegraph/index.ts`. It provides a strongly typed interface, generated based on the queries in `/src/thegraph/queries`. -- `balance`: the sum of the amount of all payments minus the sum of amount of all refunds -- `events`: all the payments and refunds events with the amount, timestamp etc... +The automated type generation is configured within files `./codegen.yml` (for EVM chains) and `./codegen-near.yml` (for Near) and output in `./src/thegraph/generated`. It depends on the deployed subgraphes schema and on the queries. -The payment networks available are: +The code generation is included in the pre-build script and can be run manually: -- `Types.Payment.PAYMENT_NETWORK_ID.BITCOIN_ADDRESS_BASED` ('pn-bitcoin-address-based'): handle Bitcoin payments associated to a BTC address to the request, every transaction hitting this address will be consider as a payment. Optionally, the payer can provide a BTC address for the refunds. Note that **the addresses must be used only for one and only one request** otherwise one transaction will be considered as a payment for more than one request. (see [the specification](https://github.com/RequestNetwork/requestNetwork/blob/master/packages/advanced-logic/specs/payment-network-btc-address-based-0.1.0.md)) -- `Types.Payment.PAYMENT_NETWORK_ID.TESTNET_BITCOIN_ADDRESS_BASED` ('pn-testnet-bitcoin-address-based'): Same as previous but for the bitcoin testnet (for test purpose) -- `Types.Payment.PAYMENT_NETWORK_ID.ERC20_ADDRESS_BASED`('pn-erc20-address-based'): Same as `BITCOIN_ADDRESS_BASED`, for ERC20 payments. -- `Types.Payment.PAYMENT_NETWORK_ID.ERC20_PROXY_CONTRACT`('pn-erc20-proxy-contract'): uses an intermediary contract to document which request is being paid, through the `PaymentReference`. (see [the specification](https://github.com/RequestNetwork/requestNetwork/blob/master/packages/advanced-logic/specs/payment-network-erc20-address-based-0.1.0.md)) -- `Types.Payment.PAYMENT_NETWORK_ID.ETH_INPUT_DATA`('pn-eth-input-data'): uses the transaction input data to pass the `PaymentReference`. (see [the specification](https://github.com/RequestNetwork/requestNetwork/blob/master/packages/advanced-logic/specs/payment-network-eth-input-data-0.1.0.md)) -- `Types.Payment.PAYMENT_NETWORK_ID.DECLARATIVE`('pn-any-declarative'): a manual alternative, where payer can declare a payment sent, and payee can declare it received, working for any currency. (see [the specification](https://github.com/RequestNetwork/requestNetwork/blob/master/packages/advanced-logic/specs/payment-network-any-declarative-0.1.0.md)) +``` +yarn codegen +``` diff --git a/packages/payment-detection/src/any/retrievers/thegraph.ts b/packages/payment-detection/src/any/retrievers/thegraph.ts index 4b41df8e75..3fba8e9799 100644 --- a/packages/payment-detection/src/any/retrievers/thegraph.ts +++ b/packages/payment-detection/src/any/retrievers/thegraph.ts @@ -1,13 +1,14 @@ -import { PaymentTypes } from '@requestnetwork/types'; import { CurrencyDefinition } from '@requestnetwork/currency'; +import { PaymentTypes } from '@requestnetwork/types'; import { BigNumber, utils } from 'ethers'; +import { IPaymentRetriever } from '../../types'; import { getTheGraphClient, TheGraphClient } from '../../thegraph'; /** * Retrieves a list of payment events from a payment reference, a destination address, a token address and a proxy contract */ export class TheGraphAnyToErc20Retriever - implements PaymentTypes.IPaymentNetworkInfoRetriever { + implements IPaymentRetriever { private client: TheGraphClient; /** diff --git a/packages/payment-detection/src/erc20/address-based-info-retriever.ts b/packages/payment-detection/src/erc20/address-based-info-retriever.ts index d7b52f22d9..58ea6d90fb 100644 --- a/packages/payment-detection/src/erc20/address-based-info-retriever.ts +++ b/packages/payment-detection/src/erc20/address-based-info-retriever.ts @@ -1,4 +1,5 @@ import { PaymentTypes } from '@requestnetwork/types'; +import { IPaymentRetriever } from '../types'; import { ethers } from 'ethers'; import { getDefaultProvider } from '../provider'; @@ -48,7 +49,7 @@ const erc20BalanceOfAbiFragment = [ * Retrieves a list of transfer events for an address */ export default class ERC20InfoRetriever - implements PaymentTypes.IPaymentNetworkInfoRetriever { + implements IPaymentRetriever { /** * @param tokenContractAddress The address of the ERC20 contract * @param address Address of the balance we want to check diff --git a/packages/payment-detection/src/erc20/escrow-info-retriever.ts b/packages/payment-detection/src/erc20/escrow-info-retriever.ts index 330dcfd329..f11a282a68 100644 --- a/packages/payment-detection/src/erc20/escrow-info-retriever.ts +++ b/packages/payment-detection/src/erc20/escrow-info-retriever.ts @@ -1,4 +1,5 @@ import { PaymentTypes } from '@requestnetwork/types'; +import { IEventRetriever } from '../types'; import { ethers } from 'ethers'; import { getDefaultProvider } from '../provider'; import { parseLogArgs } from '../utils'; @@ -20,7 +21,7 @@ type EscrowArgs = { */ export default class EscrowERC20InfoRetriever implements - PaymentTypes.IPaymentNetworkBaseInfoRetriever< + IEventRetriever< PaymentTypes.IPaymentNetworkBaseEvent, PaymentTypes.ESCROW_EVENTS_NAMES > { diff --git a/packages/payment-detection/src/erc20/proxy-info-retriever.ts b/packages/payment-detection/src/erc20/proxy-info-retriever.ts index 89ca2035df..e842931ac7 100644 --- a/packages/payment-detection/src/erc20/proxy-info-retriever.ts +++ b/packages/payment-detection/src/erc20/proxy-info-retriever.ts @@ -1,4 +1,5 @@ import { PaymentTypes } from '@requestnetwork/types'; +import { IPaymentRetriever } from '../types'; import { BigNumber, ethers } from 'ethers'; import { getDefaultProvider } from '../provider'; import { parseLogArgs } from '../utils'; @@ -27,7 +28,7 @@ type TransferWithReferenceAndFeeArgs = TransferWithReferenceArgs & { * Retrieves a list of payment events from a payment reference, a destination address, a token address and a proxy contract */ export default class ProxyERC20InfoRetriever - implements PaymentTypes.IPaymentNetworkInfoRetriever { + implements IPaymentRetriever { public contractProxy: ethers.Contract; public provider: ethers.providers.Provider; diff --git a/packages/payment-detection/src/eth/info-retriever.ts b/packages/payment-detection/src/eth/info-retriever.ts index 7b4198ee4b..c0d57697df 100644 --- a/packages/payment-detection/src/eth/info-retriever.ts +++ b/packages/payment-detection/src/eth/info-retriever.ts @@ -1,11 +1,12 @@ import { PaymentTypes } from '@requestnetwork/types'; +import { IPaymentRetriever } from '../types'; import { MultichainExplorerApiProvider } from './multichainExplorerApiProvider'; /** * Gets a list of transfer events for an address and payment reference */ export class EthInputDataInfoRetriever - implements PaymentTypes.IPaymentNetworkInfoRetriever { + implements IPaymentRetriever { /** * @param toAddress Address to check * @param eventName Indicate if it is an address for payment or refund diff --git a/packages/payment-detection/src/eth/proxy-info-retriever.ts b/packages/payment-detection/src/eth/proxy-info-retriever.ts index 7e90e9e757..1c89b0237d 100644 --- a/packages/payment-detection/src/eth/proxy-info-retriever.ts +++ b/packages/payment-detection/src/eth/proxy-info-retriever.ts @@ -1,4 +1,5 @@ import { PaymentTypes } from '@requestnetwork/types'; +import { IPaymentRetriever } from '../types'; import { BigNumber, ethers } from 'ethers'; import { getDefaultProvider } from '../provider'; import { parseLogArgs } from '../utils'; @@ -26,7 +27,7 @@ type TransferWithReferenceAndFeeArgs = TransferWithReferenceArgs & { * Retrieves a list of payment events from a payment reference, a destination address, a token address and a proxy contract */ export class EthProxyInfoRetriever - implements PaymentTypes.IPaymentNetworkInfoRetriever { + implements IPaymentRetriever { public contractProxy: ethers.Contract; public provider: ethers.providers.Provider; diff --git a/packages/payment-detection/src/payment-network-factory.ts b/packages/payment-detection/src/payment-network-factory.ts index d5eebd630c..b2d44adf12 100644 --- a/packages/payment-detection/src/payment-network-factory.ts +++ b/packages/payment-detection/src/payment-network-factory.ts @@ -5,6 +5,7 @@ import { RequestLogicTypes, } from '@requestnetwork/types'; import { ICurrencyManager } from '@requestnetwork/currency'; +import { IPaymentNetworkModuleByType, ISupportedPaymentNetworkByCurrency } from './types'; import { BtcMainnetAddressBasedDetector } from './btc/mainnet-address-based'; import { BtcTestnetAddressBasedDetector } from './btc/testnet-address-based'; import { DeclarativePaymentDetector } from './declarative'; @@ -20,7 +21,7 @@ import { AnyToEthFeeProxyPaymentDetector } from './any/any-to-eth-proxy'; const PN_ID = PaymentTypes.PAYMENT_NETWORK_ID; /** Register the payment network by currency and type */ -const supportedPaymentNetwork: PaymentTypes.ISupportedPaymentNetworkByCurrency = { +const supportedPaymentNetwork: ISupportedPaymentNetworkByCurrency = { BTC: { mainnet: { [PN_ID.BITCOIN_ADDRESS_BASED]: BtcMainnetAddressBasedDetector, @@ -48,7 +49,7 @@ const supportedPaymentNetwork: PaymentTypes.ISupportedPaymentNetworkByCurrency = }, }; -const anyCurrencyPaymentNetwork: PaymentTypes.IPaymentNetworkModuleByType = { +const anyCurrencyPaymentNetwork: IPaymentNetworkModuleByType = { [PN_ID.ANY_TO_ERC20_PROXY]: AnyToERC20PaymentDetector, [PN_ID.DECLARATIVE]: DeclarativePaymentDetector, [PN_ID.ANY_TO_ETH_PROXY]: AnyToEthFeeProxyPaymentDetector, @@ -158,7 +159,7 @@ export default class PaymentNetworkFactory { */ public static supportedPaymentNetworksForCurrency( currency: RequestLogicTypes.ICurrency, - ): PaymentTypes.IPaymentNetworkModuleByType { + ): IPaymentNetworkModuleByType { if (!supportedPaymentNetwork[currency.type]) { return anyCurrencyPaymentNetwork; } diff --git a/packages/payment-detection/src/types.ts b/packages/payment-detection/src/types.ts new file mode 100644 index 0000000000..946a482ee3 --- /dev/null +++ b/packages/payment-detection/src/types.ts @@ -0,0 +1,32 @@ +import { PaymentTypes } from '@requestnetwork/types'; + +/** Generic info retriever interface */ +export interface IPaymentRetriever< + TPaymentNetworkEvent extends PaymentTypes.IPaymentNetworkEvent, + TEventNames = PaymentTypes.EVENTS_NAMES +> { + getTransferEvents(): Promise; +} + +/** Generic info retriever interface without transfers */ +export interface IEventRetriever< + TPaymentNetworkEvent extends PaymentTypes.IPaymentNetworkBaseEvent, + TEventNames = PaymentTypes.EVENTS_NAMES +> { + getContractEvents(): Promise; +} + +/** Object interface to list the payment network module by id */ +export interface IPaymentNetworkModuleByType { + [type: string]: any; +} + +/** Object interface to list the payment network module by network */ +export interface ISupportedPaymentNetworkByNetwork { + [network: string]: IPaymentNetworkModuleByType; +} + +/** Object interface to list the payment network id and its module by currency */ +export interface ISupportedPaymentNetworkByCurrency { + [currency: string]: ISupportedPaymentNetworkByNetwork; +} diff --git a/packages/types/src/payment-types.ts b/packages/types/src/payment-types.ts index 048593ac22..5b3b66e867 100644 --- a/packages/types/src/payment-types.ts +++ b/packages/types/src/payment-types.ts @@ -3,20 +3,32 @@ import * as Extension from './extension-types'; import * as RequestLogic from './request-logic-types'; import { ICreationParameters } from './extensions/pn-any-declarative-types'; -/** Object interface to list the payment network id and its module by currency */ -export interface ISupportedPaymentNetworkByCurrency { - [currency: string]: ISupportedPaymentNetworkByNetwork; +/** List of payment networks available (abstract the extensions type) */ +export enum PAYMENT_NETWORK_ID { + BITCOIN_ADDRESS_BASED = Extension.ID.PAYMENT_NETWORK_BITCOIN_ADDRESS_BASED, + TESTNET_BITCOIN_ADDRESS_BASED = Extension.ID.PAYMENT_NETWORK_TESTNET_BITCOIN_ADDRESS_BASED, + ERC20_ADDRESS_BASED = Extension.ID.PAYMENT_NETWORK_ERC20_ADDRESS_BASED, + ERC20_PROXY_CONTRACT = Extension.ID.PAYMENT_NETWORK_ERC20_PROXY_CONTRACT, + ERC20_FEE_PROXY_CONTRACT = Extension.ID.PAYMENT_NETWORK_ERC20_FEE_PROXY_CONTRACT, + ETH_INPUT_DATA = Extension.ID.PAYMENT_NETWORK_ETH_INPUT_DATA, + ETH_FEE_PROXY_CONTRACT = Extension.ID.PAYMENT_NETWORK_ETH_FEE_PROXY_CONTRACT, + NATIVE_TOKEN = Extension.ID.PAYMENT_NETWORK_NATIVE_TOKEN, + DECLARATIVE = Extension.ID.PAYMENT_NETWORK_ANY_DECLARATIVE, + ANY_TO_ERC20_PROXY = Extension.ID.PAYMENT_NETWORK_ANY_TO_ERC20_PROXY, + ANY_TO_ETH_PROXY = Extension.ID.PAYMENT_NETWORK_ANY_TO_ETH_PROXY, } - -/** Object interface to list the payment network module by network */ -export interface ISupportedPaymentNetworkByNetwork { - [network: string]: IPaymentNetworkModuleByType; +/** Interface for payment network extensions state and interpretation */ +export interface IPaymentNetwork { + paymentNetworkId: PAYMENT_NETWORK_ID; + createExtensionsDataForCreation: (paymentNetworkCreationParameters: any) => Promise; + createExtensionsDataForAddRefundInformation: (parameters: any) => any; + createExtensionsDataForAddPaymentInformation: (parameters: any) => any; + getBalance(request: RequestLogic.IRequest): Promise>; } -/** Object interface to list the payment network module by id */ -export interface IPaymentNetworkModuleByType { - [type: string]: any; -} +/** + * Interfaces for parameters to create payment extensions + */ /** Interface to create a payment network */ export interface IPaymentNetworkCreateParameters { @@ -44,23 +56,9 @@ export interface IAnyToErc20CreationParameters extends IFeeReferenceBasedCreatio maxRateTimespan?: number; } -/** Interface of the class to manage a payment network */ -export interface IPaymentNetwork { - paymentNetworkId: PAYMENT_NETWORK_ID; - createExtensionsDataForCreation: (paymentNetworkCreationParameters: any) => Promise; - createExtensionsDataForAddRefundInformation: (parameters: any) => any; - createExtensionsDataForAddPaymentInformation: (parameters: any) => any; - getBalance(request: RequestLogic.IRequest): Promise>; -} - -/** Interface of the class to manage the bitcoin provider API */ -export interface IBitcoinDetectionProvider { - getAddressBalanceWithEvents: ( - bitcoinNetworkId: number, - address: string, - eventName: EVENTS_NAMES, - ) => Promise>; -} +/** + * Interfaces for balance and events + */ /** Interface for balances and the events link to the payments and refund */ export interface IBalanceWithEvents { @@ -75,6 +73,18 @@ export interface IBalanceError { code: BALANCE_ERROR_CODE; } +/** payment network event names */ +export enum EVENTS_NAMES { + PAYMENT = 'payment', + REFUND = 'refund', +} + +export enum ESCROW_EVENTS_NAMES { + FROZEN_PAYMENT = 'frozenPayment', + INITIATED_EMERGENCY_CLAIM = 'initiatedEmergencyClaim', + REVERTED_EMERGENCY_CLAIM = 'revertedEmergencyClaim', +} + /** Balance error codes */ export enum BALANCE_ERROR_CODE { UNKNOWN, @@ -95,48 +105,25 @@ export interface IPaymentNetworkEvent, - TEventNames = EVENTS_NAMES -> { - getTransferEvents(): Promise; +/** Parameters for events of Declarative payments */ +export interface IDeclarativePaymentEventParameters { + txHash?: string; + network?: string; + note?: string; + from?: IIdentity; } +/** Declarative Payment Network Event */ +export type DeclarativePaymentNetworkEvent = IPaymentNetworkEvent; +/** Declarative BalanceWithEvents */ +export type DeclarativeBalanceWithEvents = IBalanceWithEvents; -/** Generic info retriever interface without transfers */ -export interface IPaymentNetworkBaseInfoRetriever< - TPaymentNetworkEvent extends IPaymentNetworkBaseEvent, - TEventNames = EVENTS_NAMES -> { - getContractEvents(): Promise; -} +/** + * ERC20 networks and events + */ /** Parameters for events of ERC20 payments */ export interface IERC20PaymentEventParameters { @@ -162,6 +149,10 @@ export type ERC20PaymentNetworkEvent = IPaymentNetworkEvent< /** ERC20 BalanceWithEvents */ export type ERC20BalanceWithEvents = IBalanceWithEvents; +/** + * Conversion-related events + */ + export type ConversionPaymentNetworkEventParameters = | IERC20PaymentEventParameters | IERC20FeePaymentEventParameters @@ -169,6 +160,10 @@ export type ConversionPaymentNetworkEventParameters = | IETHFeePaymentEventParameters; export type ConversionPaymentNetworkEvent = IPaymentNetworkEvent; +/** + * ETH and native token balance and events + */ + /** Parameters for events of ETH payments */ export interface IETHPaymentEventParameters { block?: number; @@ -192,6 +187,19 @@ export type ETHBalanceWithEvents = IBalanceWithEvents< IETHPaymentEventParameters | IETHFeePaymentEventParameters >; +/** + * Bitcoin provider and events + */ + +/** Interface of the class to manage the bitcoin provider API */ +export interface IBitcoinDetectionProvider { + getAddressBalanceWithEvents: ( + bitcoinNetworkId: number, + address: string, + eventName: EVENTS_NAMES, + ) => Promise>; +} + /** Parameters for events of BTC payments */ export interface IBTCPaymentEventParameters { block?: number; @@ -201,15 +209,3 @@ export interface IBTCPaymentEventParameters { export type BTCPaymentNetworkEvent = IPaymentNetworkEvent; /** BTC BalanceWithEvents */ export type BTCBalanceWithEvents = IBalanceWithEvents; - -/** Parameters for events of Declarative payments */ -export interface IDeclarativePaymentEventParameters { - txHash?: string; - network?: string; - note?: string; - from?: IIdentity; -} -/** Declarative Payment Network Event */ -export type DeclarativePaymentNetworkEvent = IPaymentNetworkEvent; -/** Declarative BalanceWithEvents */ -export type DeclarativeBalanceWithEvents = IBalanceWithEvents;