Skip to content

Commit

Permalink
feat: add generic rfq implementation
Browse files Browse the repository at this point in the history
Resolves BACK-760.
  • Loading branch information
Louis-Amas committed Oct 18, 2022
1 parent d7a6f21 commit 7d3a3cc
Show file tree
Hide file tree
Showing 16 changed files with 1,251 additions and 9 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
"access": "public"
},
"devDependencies": {
"@paraswap/sdk": "^6.0.0",
"@types/axios": "0.14.0",
"@types/express": "^4.17.14",
"@types/jest": "26.0.24",
"@types/lodash": "4.14.178",
"@types/node": "^17.0.21",
"axios": "0.26.0",
"change-case": "^4.1.2",
"dotenv": "16.0.0",
"express": "^4.18.2",
"husky": "7.0.1",
"jest": "^29.0.3",
"paraswap-core": "1.0.2",
Expand Down
46 changes: 45 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Config, Address, Token } from './types';
import { Network } from './constants';
import { Network, PORT_TEST_SERVER } from './constants';
import { isETHAddress } from './utils';
import { ETHER_ADDRESS } from 'paraswap';
import { RFQConfig } from './dex/generic-rfq/types';

// Hardcoded and environment values from which actual config is derived
type BaseConfig = {
Expand All @@ -16,11 +17,13 @@ type BaseConfig = {
wrappedNativeTokenAddress: Address;
hasEIP1559: boolean;
augustusAddress: Address;
augustusRFQAddress: Address;
tokenTransferProxyAddress: Address;
multicallV2Address: Address;
privateHttpProvider?: string;
adapterAddresses: { [name: string]: Address };
uniswapV2ExchangeRouterAddress: Address;
rfqConfigs: Record<string, RFQConfig>;
};

const baseConfigs: { [network: number]: BaseConfig } = {
Expand All @@ -33,6 +36,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
hasEIP1559: true,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0xe92b586627ccA7a83dC919cc7127196d70f55a06',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
privateHttpProvider: process.env.HTTP_PROVIDER,
Expand All @@ -44,6 +48,30 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0xF9234CB08edb93c0d4a4d4c70cC3FfD070e78e07',
rfqConfigs: {
DummyParaSwapPool: {
marketConfig: {
reqParams: {
url: `http://localhost:${PORT_TEST_SERVER}/markets`,
method: 'GET',
},
intervalMs: 1000 * 60 * 60 * 10, // every 10 minutes
dataTTLS: 1000 * 60 * 60 * 11, // tll 11 minutes
},
rateConfig: {
reqParams: {
url: `http://localhost:${PORT_TEST_SERVER}/prices`,
method: 'GET',
},
intervalMs: 1000 * 60 * 60 * 1, // every 1 minute
dataTTLS: 1000 * 60 * 60 * 1, // tll 1 minute
},
firmRateConfig: {
url: `http://localhost:${PORT_TEST_SERVER}/firm`,
method: 'POST',
},
},
},
},
[Network.ROPSTEN]: {
network: Network.ROPSTEN,
Expand All @@ -55,6 +83,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0xc778417E063141139Fce010982780140Aa0cD5Ab',
hasEIP1559: true,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0x34268C38fcbC798814b058656bC0156C7511c0E4',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
privateHttpProvider: process.env.HTTP_PROVIDER_3,
Expand All @@ -64,6 +93,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0x53e693c6C7FFC4446c53B205Cf513105Bf140D7b',
rfqConfigs: {},
},
[Network.BSC]: {
network: Network.BSC,
Expand All @@ -73,6 +103,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c',
hasEIP1559: false,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0x8DcDfe88EF0351f27437284D0710cD65b20288bb',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0xC50F4c1E81c873B2204D7eFf7069Ffec6Fbe136D',
privateHttpProvider: process.env.HTTP_PROVIDER_56,
Expand All @@ -83,6 +114,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0x53e693c6C7FFC4446c53B205Cf513105Bf140D7b',
rfqConfigs: {},
},
[Network.POLYGON]: {
network: Network.POLYGON,
Expand All @@ -93,6 +125,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
hasEIP1559: true,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0xF3CD476C3C4D3Ac5cA2724767f269070CA09A043',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0x275617327c958bD06b5D6b871E7f491D76113dd8',
privateHttpProvider: process.env.HTTP_PROVIDER_137,
Expand All @@ -103,6 +136,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0xf3938337F7294fEf84e9B2c6D548A93F956Cc281',
rfqConfigs: {},
},
[Network.AVALANCHE]: {
network: Network.AVALANCHE,
Expand All @@ -113,6 +147,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
hasEIP1559: true,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0x34302c4267d0dA0A8c65510282Cc22E9e39df51f',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0xd7Fc8aD069f95B6e2835f4DEff03eF84241cF0E1',
privateHttpProvider: process.env.HTTP_PROVIDER_43114,
Expand All @@ -122,6 +157,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0x53e693c6C7FFC4446c53B205Cf513105Bf140D7b',
rfqConfigs: {},
},
[Network.FANTOM]: {
network: Network.FANTOM,
Expand All @@ -132,6 +168,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83',
hasEIP1559: false,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0x2DF17455B96Dde3618FD6B1C3a9AA06D6aB89347',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0xdC6E2b14260F972ad4e5a31c68294Fba7E720701',
privateHttpProvider: process.env.HTTP_PROVIDER_250,
Expand All @@ -141,6 +178,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0xAB86e2bC9ec5485a9b60E684BA6d49bf4686ACC2',
rfqConfigs: {},
},
[Network.ARBITRUM]: {
network: Network.ARBITRUM,
Expand All @@ -151,6 +189,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
hasEIP1559: false,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0x0927FD43a7a87E3E8b81Df2c44B03C4756849F6D',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0x7eCfBaa8742fDf5756DAC92fbc8b90a19b8815bF',
privateHttpProvider: process.env.HTTP_PROVIDER_42161,
Expand All @@ -160,6 +199,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0xB41dD984730dAf82f5C41489E21ac79D5e3B61bC',
rfqConfigs: {},
},
[Network.OPTIMISM]: {
network: Network.OPTIMISM,
Expand All @@ -170,6 +210,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
wrappedNativeTokenAddress: '0x4200000000000000000000000000000000000006',
hasEIP1559: false,
augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57',
augustusRFQAddress: '0x0927FD43a7a87E3E8b81Df2c44B03C4756849F6D',
tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae',
multicallV2Address: '0x2DC0E2aa608532Da689e89e237dF582B783E552C',
privateHttpProvider: process.env.HTTP_PROVIDER_10,
Expand All @@ -179,6 +220,7 @@ const baseConfigs: { [network: number]: BaseConfig } = {
},
uniswapV2ExchangeRouterAddress:
'0xB41dD984730dAf82f5C41489E21ac79D5e3B61bC',
rfqConfigs: {},
},
};

Expand Down Expand Up @@ -207,11 +249,13 @@ export function generateConfig(network: number): Config {
wrappedNativeTokenAddress: baseConfig.wrappedNativeTokenAddress,
hasEIP1559: baseConfig.hasEIP1559,
augustusAddress: baseConfig.augustusAddress,
augustusRFQAddress: baseConfig.augustusRFQAddress,
tokenTransferProxyAddress: baseConfig.tokenTransferProxyAddress,
multicallV2Address: baseConfig.multicallV2Address,
privateHttpProvider: baseConfig.privateHttpProvider,
adapterAddresses: { ...baseConfig.adapterAddresses },
uniswapV2ExchangeRouterAddress: baseConfig.uniswapV2ExchangeRouterAddress,
rfqConfigs: {},
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Address } from './types';
export { SwapSide, ContractMethod } from 'paraswap-core';

export const PORT_TEST_SERVER = 4444;

export const ETHER_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';

Expand Down
5 changes: 5 additions & 0 deletions src/dex-helper/dummy-dex-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Web3 from 'web3';
import { Contract } from 'web3-eth-contract';
import { generateConfig, ConfigHelper } from '../config';
import { MultiWrapper } from '../lib/multi-wrapper';
import { Response, RequestConfig } from './irequest-wrapper';

// This is a dummy cache for testing purposes
class DummyCache implements ICache {
Expand Down Expand Up @@ -96,6 +97,10 @@ class DummyRequestWrapper implements IRequestWrapper {
});
return axiosResult.data;
}

request<T = any, R = Response<T>>(config: RequestConfig<any>): Promise<R> {
return axios.request(config);
}
}

class DummyBlockManager implements IBlockManager {
Expand Down
44 changes: 44 additions & 0 deletions src/dex-helper/irequest-wrapper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
export type Method =
| 'get'
| 'GET'
| 'delete'
| 'DELETE'
| 'head'
| 'HEAD'
| 'options'
| 'OPTIONS'
| 'post'
| 'POST'
| 'put'
| 'PUT'
| 'patch'
| 'PATCH'
| 'purge'
| 'PURGE'
| 'link'
| 'LINK'
| 'unlink'
| 'UNLINK';

export type RequestHeaders = Record<string, string | number | boolean>;

export interface RequestConfig<D = any> {
url?: string;
method?: Method;
headers?: RequestHeaders;
params?: any;
paramsSerializer?: (params: any) => string;
data?: D;
timeout?: number;
}

export interface Response<T = any> {
data: T;
status: number;
statusText: string;
headers: Record<string, string>;
request?: any;
}

export interface IRequestWrapper {
get<T>(
url: string,
Expand All @@ -11,4 +53,6 @@ export interface IRequestWrapper {
timeout?: number,
headers?: { [key: string]: string | number },
): Promise<T>;

request<T = any, R = Response<T>>(config: RequestConfig): Promise<R>;
}
63 changes: 63 additions & 0 deletions src/dex/generic-rfq/example-api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import express from 'express';

const app = express();

const markets = {
id: 'WETH-DAI',
base: {
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
decimals: 18,
type: 'erc20',
},
quote: {
address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
decimals: 18,
type: 'erc20',
},
status: 'available',
};

const prices = {
'WETH-DAI': {
buyAmounts: [
'1.166200000000000000',
'1.166200000000000000',
'1.166200000000000000',
'1.166200000000000000',
'1.166200000000000000',
'1.169000000000000000',
],
buyPrices: [
'1333.425240000000000000',
'1333.024812000000000000',
'1332.624384000000000000',
'1332.223956000000000000',
'1331.823528000000000000',
'1331.423100000000000000',
],
sellAmounts: [
'1.166200000000000000',
'1.166200000000000000',
'1.166200000000000000',
'1.166200000000000000',
'1.166200000000000000',
'1.169000000000000000',
],
sellPrices: [
'1336.745410000000000000',
'1337.146033000000000000',
'1337.546656000000000000',
'1337.947279000000000000',
'1338.347902000000000000',
'1338.748525000000000000',
],
},
};

app.get('/markets', (req, res) => {
return res.status(200).json(markets);
});

app.get('/prices', (req, res) => {
return res.status(200).json(prices);
});
38 changes: 38 additions & 0 deletions src/dex/generic-rfq/generic-rfq-e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import dotenv from 'dotenv';
dotenv.config();

import { Network, ContractMethod, SwapSide } from '../../constants';
import { StaticJsonRpcProvider } from '@ethersproject/providers';
import { generateConfig } from '../../config';
import { testE2E } from '../../../tests/utils-e2e';
import { Tokens, Holders } from '../../../tests/constants-e2e';

describe('GenericRFQ E2E Mainnet', () => {
const network = Network.MAINNET;
const tokens = Tokens[network];
const holders = Holders[network];
const provider = new StaticJsonRpcProvider(
generateConfig(network).privateHttpProvider,
network,
);

describe('GenericRFQ', () => {
const dexKey = 'GenericRFQ';

describe('Simpleswap', () => {
it('ETH -> TOKEN', async () => {
await testE2E(
tokens.ETH,
tokens.USDC,
holders.ETH,
'7000000000000000000',
SwapSide.SELL,
dexKey,
ContractMethod.simpleSwap,
network,
provider,
);
});
});
});
});
Loading

0 comments on commit 7d3a3cc

Please sign in to comment.