Skip to content

Commit

Permalink
chore(payment-detection): clean Retrievers type. Document. (#752)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
yomarion committed Jan 31, 2022
1 parent 803159e commit ca40537
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 101 deletions.
67 changes: 55 additions & 12 deletions packages/payment-detection/README.md
Original file line number Diff line number Diff line change
@@ -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<TPaymentEventParameters> {
public async getBalance(
request: RequestLogicTypes.IRequest,
): Promise<PaymentTypes.IBalanceWithEvents<TPaymentEventParameters>> {
// ...

// 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
```
5 changes: 3 additions & 2 deletions packages/payment-detection/src/any/retrievers/thegraph.ts
Original file line number Diff line number Diff line change
@@ -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<PaymentTypes.ERC20PaymentNetworkEvent> {
implements IPaymentRetriever<PaymentTypes.ERC20PaymentNetworkEvent> {
private client: TheGraphClient;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PaymentTypes } from '@requestnetwork/types';
import { IPaymentRetriever } from '../types';
import { ethers } from 'ethers';
import { getDefaultProvider } from '../provider';

Expand Down Expand Up @@ -48,7 +49,7 @@ const erc20BalanceOfAbiFragment = [
* Retrieves a list of transfer events for an address
*/
export default class ERC20InfoRetriever
implements PaymentTypes.IPaymentNetworkInfoRetriever<PaymentTypes.ERC20PaymentNetworkEvent> {
implements IPaymentRetriever<PaymentTypes.ERC20PaymentNetworkEvent> {
/**
* @param tokenContractAddress The address of the ERC20 contract
* @param address Address of the balance we want to check
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -20,7 +21,7 @@ type EscrowArgs = {
*/
export default class EscrowERC20InfoRetriever
implements
PaymentTypes.IPaymentNetworkBaseInfoRetriever<
IEventRetriever<
PaymentTypes.IPaymentNetworkBaseEvent<PaymentTypes.ESCROW_EVENTS_NAMES>,
PaymentTypes.ESCROW_EVENTS_NAMES
> {
Expand Down
3 changes: 2 additions & 1 deletion packages/payment-detection/src/erc20/proxy-info-retriever.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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<PaymentTypes.ERC20PaymentNetworkEvent> {
implements IPaymentRetriever<PaymentTypes.ERC20PaymentNetworkEvent> {
public contractProxy: ethers.Contract;
public provider: ethers.providers.Provider;

Expand Down
3 changes: 2 additions & 1 deletion packages/payment-detection/src/eth/info-retriever.ts
Original file line number Diff line number Diff line change
@@ -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<PaymentTypes.ETHPaymentNetworkEvent> {
implements IPaymentRetriever<PaymentTypes.ETHPaymentNetworkEvent> {
/**
* @param toAddress Address to check
* @param eventName Indicate if it is an address for payment or refund
Expand Down
3 changes: 2 additions & 1 deletion packages/payment-detection/src/eth/proxy-info-retriever.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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<PaymentTypes.ETHPaymentNetworkEvent> {
implements IPaymentRetriever<PaymentTypes.ETHPaymentNetworkEvent> {
public contractProxy: ethers.Contract;
public provider: ethers.providers.Provider;

Expand Down
7 changes: 4 additions & 3 deletions packages/payment-detection/src/payment-network-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -158,7 +159,7 @@ export default class PaymentNetworkFactory {
*/
public static supportedPaymentNetworksForCurrency(
currency: RequestLogicTypes.ICurrency,
): PaymentTypes.IPaymentNetworkModuleByType {
): IPaymentNetworkModuleByType {
if (!supportedPaymentNetwork[currency.type]) {
return anyCurrencyPaymentNetwork;
}
Expand Down
32 changes: 32 additions & 0 deletions packages/payment-detection/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PaymentTypes } from '@requestnetwork/types';

/** Generic info retriever interface */
export interface IPaymentRetriever<
TPaymentNetworkEvent extends PaymentTypes.IPaymentNetworkEvent<unknown, TEventNames>,
TEventNames = PaymentTypes.EVENTS_NAMES
> {
getTransferEvents(): Promise<TPaymentNetworkEvent[]>;
}

/** Generic info retriever interface without transfers */
export interface IEventRetriever<
TPaymentNetworkEvent extends PaymentTypes.IPaymentNetworkBaseEvent<TEventNames>,
TEventNames = PaymentTypes.EVENTS_NAMES
> {
getContractEvents(): Promise<TPaymentNetworkEvent[]>;
}

/** 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;
}
Loading

0 comments on commit ca40537

Please sign in to comment.