Skip to content

Commit

Permalink
Merge branch 'master' into erc20SwapToPay_with_fees
Browse files Browse the repository at this point in the history
  • Loading branch information
Dadogg80 committed Feb 1, 2022
2 parents e49d4be + ca40537 commit fda7945
Show file tree
Hide file tree
Showing 27 changed files with 408 additions and 290 deletions.
Expand Up @@ -25,6 +25,7 @@ export default class Erc20FeeProxyPaymentNetwork<
'bsc',
'xdai',
'fantom',
'arbitrum-rinkeby',
],
public supportedCurrencyType: RequestLogicTypes.CURRENCY = RequestLogicTypes.CURRENCY.ERC20,
) {
Expand Down
Expand Up @@ -13,6 +13,7 @@ const supportedNetworks = [
'fantom',
'bsctest',
'bsc',
'arbitrum-rinkeby',
];

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/currency/src/native.ts
Expand Up @@ -76,10 +76,10 @@ export const nativeCurrencies: Record<NativeCurrencyType, (NativeCurrency & { na
network: 'aurora-testnet',
},
{
symbol: 'ARETH testnet',
symbol: 'ARETH',
decimals: 18,
name: 'Arbitrum Testnet',
network: 'arbitrum-testnet',
network: 'arbitrum-rinkeby',
},
],
[RequestLogicTypes.CURRENCY.BTC]: [
Expand Down
67 changes: 55 additions & 12 deletions 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<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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
1 change: 1 addition & 0 deletions packages/payment-detection/src/provider.ts
Expand Up @@ -39,6 +39,7 @@ const networkRpcs: Record<string, string> = {
bsctest: 'https://data-seed-prebsc-1-s1.binance.org:8545',
bsc: 'https://bsc-dataseed1.binance.org/',
xdai: 'https://rpc.xdaichain.com/',
'arbitrum-rinkeby': 'https://rinkeby.arbitrum.io/rpc',
};

/**
Expand Down
32 changes: 32 additions & 0 deletions 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<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;
}
23 changes: 15 additions & 8 deletions packages/smart-contracts/hardhat.config.ts
Expand Up @@ -5,12 +5,9 @@ import '@nomiclabs/hardhat-etherscan';
import '@nomiclabs/hardhat-ethers';
import { task } from 'hardhat/config';
import { config } from 'dotenv';
import deployRequest from './scripts/1_deploy-request-storage';
import deployPayment from './scripts/2_deploy-main-payments';
import deployConversion from './scripts/3_deploy_chainlink_contract';
import deployAllContracts from './scripts/5_deploy-all';
import { deployAllPaymentContracts } from './scripts/deploy-payments';
import { preparePayments } from './scripts/prepare-payments';
import { deployEscrow } from './scripts/4_deploy-escrow-deployment';

import { HardhatRuntimeEnvironment } from 'hardhat/types';

Expand Down Expand Up @@ -78,6 +75,16 @@ export default {
chainId: 250,
accounts,
},
'arbitrum-one': {
url: process.env.WEB3_PROVIDER_URL || 'https://arb1.arbitrum.io/rpc',
chainId: 42161,
accounts,
},
'arbitrum-rinkeby': {
url: process.env.WEB3_PROVIDER_URL || 'https://rinkeby.arbitrum.io/rpc',
chainId: 421611,
accounts,
},
},
etherscan: {
// Can be overridden according to the network (set-explorer-api-key)
Expand All @@ -88,6 +95,9 @@ export default {
target: 'ethers-v5',
alwaysGenerateOverloads: false, // should overloads with full signatures like deposit(uint256) be generated always, even if there are no overloads?
},
mocha: {
timeout: 60000, // Usefull on test networks
},
};

// Override the default API key for non-Etherscan explorers
Expand All @@ -113,10 +123,7 @@ const setExplorerApiKey = (hre: HardhatRuntimeEnvironment) => {
// FIXME: use deployAllPaymentContracts instead to test with the same deployments
task('deploy-local-env', 'Deploy a local environment').setAction(async (args, hre) => {
args.force = true;
await deployRequest(args, hre);
await deployPayment(args, hre);
await deployConversion(args, hre);
await deployEscrow(hre);
await deployAllContracts(args, hre);
console.log('All contracts (re)deployed locally');
});

Expand Down
10 changes: 8 additions & 2 deletions packages/smart-contracts/scripts/2_deploy-main-payments.ts
Expand Up @@ -3,7 +3,7 @@ import { HardhatRuntimeEnvironment } from 'hardhat/types';
import { deployOne } from '../scripts/deploy-one';

// Deploys, set up the contracts
export default async function deploy(args: any, hre: HardhatRuntimeEnvironment) {
export default async function deploy(args: any, hre: HardhatRuntimeEnvironment): Promise<any> {
try {
const [deployer] = await hre.ethers.getSigners();

Expand Down Expand Up @@ -109,7 +109,13 @@ export default async function deploy(args: any, hre: HardhatRuntimeEnvironment)
ERC20Alpha: ${erc20AlphaInstance.address}
FakeSwapRouter: ${FakeSwapRouterAddress}
SwapToPay: ${ERC20SwapToPayAddress}
`);
`);
return {
DAIAddress: erc20AlphaInstance.address,
ERC20FeeProxyAddress: ERC20FeeProxyAddress,
ERC20TestAddress: testERC20Instance.address,
ETHFeeProxyAddress: EthereumFeeProxyAddress,
};
} catch (e) {
console.error(e);
}
Expand Down

0 comments on commit fda7945

Please sign in to comment.