@paraswap/dex-lib 3.8.38 → 3.8.39-bebop
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/abi/USDM.json +807 -0
- package/build/abi/bebop/BebopSettlement.abi.json +2137 -0
- package/build/abi/wUSDM.json +757 -0
- package/build/config.js +7 -0
- package/build/config.js.map +1 -1
- package/build/dex/bebop/bebop.d.ts +55 -0
- package/build/dex/bebop/bebop.js +524 -0
- package/build/dex/bebop/bebop.js.map +1 -0
- package/build/dex/bebop/config.d.ts +3 -0
- package/build/dex/bebop/config.js +38 -0
- package/build/dex/bebop/config.js.map +1 -0
- package/build/dex/bebop/constants.d.ts +9 -0
- package/build/dex/bebop/constants.js +13 -0
- package/build/dex/bebop/constants.js.map +1 -0
- package/build/dex/bebop/rate-fetcher.d.ts +22 -0
- package/build/dex/bebop/rate-fetcher.js +80 -0
- package/build/dex/bebop/rate-fetcher.js.map +1 -0
- package/build/dex/bebop/types.d.ts +76 -0
- package/build/dex/bebop/types.js +3 -0
- package/build/dex/bebop/types.js.map +1 -0
- package/build/dex/bebop/validators.d.ts +4 -0
- package/build/dex/bebop/validators.js +42 -0
- package/build/dex/bebop/validators.js.map +1 -0
- package/build/dex/bebop/websocket-fetcher.d.ts +35 -0
- package/build/dex/bebop/websocket-fetcher.js +87 -0
- package/build/dex/bebop/websocket-fetcher.js.map +1 -0
- package/build/dex/index.js +2 -0
- package/build/dex/index.js.map +1 -1
- package/build/dex/woo-fi-v2/woo-fi-v2-pool.d.ts +2 -2
- package/build/dex/woo-fi-v2/woo-fi-v2-pool.js +30 -9
- package/build/dex/woo-fi-v2/woo-fi-v2-pool.js.map +1 -1
- package/build/dex/woo-fi-v2/woo-fi-v2.js +1 -1
- package/build/dex/woo-fi-v2/woo-fi-v2.js.map +1 -1
- package/build/dex/wusdm/config.d.ts +3 -0
- package/build/dex/wusdm/config.js +29 -0
- package/build/dex/wusdm/config.js.map +1 -0
- package/build/dex/wusdm/types.d.ts +10 -0
- package/build/dex/wusdm/types.js +3 -0
- package/build/dex/wusdm/types.js.map +1 -0
- package/build/dex/wusdm/wusdm.d.ts +39 -0
- package/build/dex/wusdm/wusdm.js +212 -0
- package/build/dex/wusdm/wusdm.js.map +1 -0
- package/build/lib/fetcher/wsFetcher.d.ts +35 -0
- package/build/lib/fetcher/wsFetcher.js +87 -0
- package/build/lib/fetcher/wsFetcher.js.map +1 -0
- package/build/types.d.ts +1 -0
- package/package.json +4 -2
- package/src/abi/bebop/BebopSettlement.abi.json +2137 -0
- package/src/config.ts +8 -0
- package/src/dex/bebop/bebop-e2e.test.ts +195 -0
- package/src/dex/bebop/bebop-integration.test.ts +170 -0
- package/src/dex/bebop/bebop.ts +732 -0
- package/src/dex/bebop/config.ts +37 -0
- package/src/dex/bebop/constants.ts +9 -0
- package/src/dex/bebop/rate-fetcher.ts +138 -0
- package/src/dex/bebop/types.ts +81 -0
- package/src/dex/bebop/validators.ts +43 -0
- package/src/dex/index.ts +2 -0
- package/src/dex/woo-fi-v2/woo-fi-v2-pool.ts +58 -27
- package/src/dex/woo-fi-v2/woo-fi-v2.ts +1 -2
- package/src/lib/fetcher/wsFetcher.ts +126 -0
- package/src/types.ts +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DexParams } from './types';
|
|
2
|
+
import { DexConfigMap } from '../../types';
|
|
3
|
+
import { Network } from '../../constants';
|
|
4
|
+
|
|
5
|
+
export const BebopConfig: DexConfigMap<DexParams> = {
|
|
6
|
+
Bebop: {
|
|
7
|
+
[Network.MAINNET]: {
|
|
8
|
+
settlementAddress: '0xbbbbbBB520d69a9775E85b458C58c648259FAD5F',
|
|
9
|
+
chainName: 'ethereum',
|
|
10
|
+
middleTokens: [
|
|
11
|
+
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
|
|
12
|
+
'0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
|
|
13
|
+
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
[Network.ARBITRUM]: {
|
|
17
|
+
settlementAddress: '0xbbbbbBB520d69a9775E85b458C58c648259FAD5F',
|
|
18
|
+
chainName: 'arbitrum',
|
|
19
|
+
middleTokens: [
|
|
20
|
+
'0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', // USDC.e
|
|
21
|
+
'0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC
|
|
22
|
+
'0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', // USDT
|
|
23
|
+
'0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', // WETH
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
[Network.BASE]: {
|
|
27
|
+
settlementAddress: '0xbbbbbBB520d69a9775E85b458C58c648259FAD5F',
|
|
28
|
+
chainName: 'base',
|
|
29
|
+
middleTokens: ['0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'],
|
|
30
|
+
},
|
|
31
|
+
[Network.OPTIMISM]: {
|
|
32
|
+
settlementAddress: '0xbbbbbBB520d69a9775E85b458C58c648259FAD5F',
|
|
33
|
+
chainName: 'optimism',
|
|
34
|
+
middleTokens: ['0x7F5c764cBc14f9669B88837ca1490cCa17c31607'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const BEBOP_INIT_TIMEOUT_MS = 5000;
|
|
2
|
+
export const BEBOP_PRICES_CACHE_TTL = 10;
|
|
3
|
+
export const BEBOP_TOKENS_CACHE_TTL = 60;
|
|
4
|
+
export const BEBOP_TOKENS_POLLING_INTERVAL_MS = 30 * 1000;
|
|
5
|
+
export const BEBOP_API_URL = 'https://api.bebop.xyz';
|
|
6
|
+
export const BEBOP_WS_API_URL = 'wss://api.bebop.xyz';
|
|
7
|
+
export const BEBOP_GAS_COST = 120_000;
|
|
8
|
+
export const BEBOP_AUTH_NAME = 'paraswap';
|
|
9
|
+
export const BEBOP_QUOTE_TIMEOUT_MS = 2000;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ETHER_ADDRESS, Network } from '../../constants';
|
|
2
|
+
import { IDexHelper } from '../../dex-helper';
|
|
3
|
+
import { Fetcher } from '../../lib/fetcher/fetcher';
|
|
4
|
+
import { validateAndCast } from '../../lib/validators';
|
|
5
|
+
import { Logger, Token } from '../../types';
|
|
6
|
+
import {
|
|
7
|
+
BebopPricingResponse,
|
|
8
|
+
BebopRateFetcherConfig,
|
|
9
|
+
BebopTokensResponse,
|
|
10
|
+
} from './types';
|
|
11
|
+
import { pricesResponseValidator, tokensResponseValidator } from './validators';
|
|
12
|
+
import { WebSocketFetcher } from '../../lib/fetcher/wsFetcher';
|
|
13
|
+
|
|
14
|
+
export class RateFetcher {
|
|
15
|
+
private pricesFetcher: WebSocketFetcher<BebopPricingResponse>;
|
|
16
|
+
private pricesCacheKey: string;
|
|
17
|
+
private pricesCacheTTL: number;
|
|
18
|
+
|
|
19
|
+
private tokensFetcher: Fetcher<BebopTokensResponse>;
|
|
20
|
+
private tokensAddrCacheKey: string;
|
|
21
|
+
private tokensCacheKey: string;
|
|
22
|
+
private tokensCacheTTL: number;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
private dexHelper: IDexHelper,
|
|
26
|
+
private dexKey: string,
|
|
27
|
+
private network: Network,
|
|
28
|
+
private logger: Logger,
|
|
29
|
+
config: BebopRateFetcherConfig,
|
|
30
|
+
) {
|
|
31
|
+
this.pricesCacheKey = config.rateConfig.pricesCacheKey;
|
|
32
|
+
this.pricesCacheTTL = config.rateConfig.pricesCacheTTLSecs;
|
|
33
|
+
this.pricesFetcher = new WebSocketFetcher<BebopPricingResponse>(
|
|
34
|
+
{
|
|
35
|
+
info: {
|
|
36
|
+
requestOptions: config.rateConfig.pricesReqParams,
|
|
37
|
+
caster: (data: unknown) => {
|
|
38
|
+
return validateAndCast<BebopPricingResponse>(
|
|
39
|
+
data,
|
|
40
|
+
pricesResponseValidator,
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
handler: this.handlePricesResponse.bind(this),
|
|
45
|
+
},
|
|
46
|
+
logger,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
this.tokensAddrCacheKey = config.rateConfig.tokensAddrCacheKey;
|
|
50
|
+
this.tokensCacheKey = config.rateConfig.tokensCacheKey;
|
|
51
|
+
this.tokensCacheTTL = config.rateConfig.tokensCacheTTLSecs;
|
|
52
|
+
this.tokensFetcher = new Fetcher<BebopTokensResponse>(
|
|
53
|
+
dexHelper.httpRequest,
|
|
54
|
+
{
|
|
55
|
+
info: {
|
|
56
|
+
requestOptions: config.rateConfig.tokensReqParams,
|
|
57
|
+
caster: (data: unknown) => {
|
|
58
|
+
return validateAndCast<BebopTokensResponse>(
|
|
59
|
+
data,
|
|
60
|
+
tokensResponseValidator,
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
handler: this.handleTokensResponse.bind(this),
|
|
65
|
+
},
|
|
66
|
+
config.rateConfig.tokensIntervalMs,
|
|
67
|
+
logger,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
start() {
|
|
72
|
+
this.pricesFetcher.startPolling();
|
|
73
|
+
this.tokensFetcher.startPolling();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
stop() {
|
|
77
|
+
this.pricesFetcher.stopPolling();
|
|
78
|
+
this.tokensFetcher.stopPolling();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private handleTokensResponse(resp: BebopTokensResponse): void {
|
|
82
|
+
const tokenMap: { [address: string]: Token } = {};
|
|
83
|
+
const tokenAddrMap: { [symbol: string]: Token } = {};
|
|
84
|
+
|
|
85
|
+
Object.keys(resp.tokens).forEach(tokenSymbol => {
|
|
86
|
+
const token = resp.tokens[tokenSymbol];
|
|
87
|
+
const tokenData = {
|
|
88
|
+
address: token.contractAddress.toLowerCase(),
|
|
89
|
+
symbol: token.ticker,
|
|
90
|
+
decimals: token.decimals,
|
|
91
|
+
};
|
|
92
|
+
tokenAddrMap[token.contractAddress.toLowerCase()] = tokenData;
|
|
93
|
+
tokenMap[token.ticker.toLowerCase()] = tokenData;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this.dexHelper.cache.setex(
|
|
97
|
+
this.dexKey,
|
|
98
|
+
this.network,
|
|
99
|
+
this.tokensCacheKey,
|
|
100
|
+
this.tokensCacheTTL,
|
|
101
|
+
JSON.stringify(tokenMap),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
this.dexHelper.cache.setex(
|
|
105
|
+
this.dexKey,
|
|
106
|
+
this.network,
|
|
107
|
+
this.tokensAddrCacheKey,
|
|
108
|
+
this.tokensCacheTTL,
|
|
109
|
+
JSON.stringify(tokenAddrMap),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private handlePricesResponse(resp: BebopPricingResponse): void {
|
|
114
|
+
const wethAddress =
|
|
115
|
+
this.dexHelper.config.data.wrappedNativeTokenAddress.toLowerCase();
|
|
116
|
+
const normalizedPrices: BebopPricingResponse = {};
|
|
117
|
+
for (const [pair, levels] of Object.entries(resp)) {
|
|
118
|
+
normalizedPrices[pair.toLowerCase()] = levels;
|
|
119
|
+
const [base, quote] = pair.split('/');
|
|
120
|
+
// Also enter native token prices. Pricing doesn't come with these
|
|
121
|
+
if (
|
|
122
|
+
base.toLowerCase() === wethAddress ||
|
|
123
|
+
quote.toLowerCase() === wethAddress
|
|
124
|
+
) {
|
|
125
|
+
const nativePair = pair.replace(base, ETHER_ADDRESS);
|
|
126
|
+
normalizedPrices[nativePair.toLowerCase()] = levels;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.dexHelper.cache.setex(
|
|
131
|
+
this.dexKey,
|
|
132
|
+
this.network,
|
|
133
|
+
this.pricesCacheKey,
|
|
134
|
+
this.pricesCacheTTL,
|
|
135
|
+
JSON.stringify(normalizedPrices),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { SwapSide } from '../../constants';
|
|
2
|
+
import { RequestHeaders } from '../../dex-helper';
|
|
3
|
+
|
|
4
|
+
export type BebopRateFetcherConfig = {
|
|
5
|
+
rateConfig: {
|
|
6
|
+
pricesReqParams: {
|
|
7
|
+
url: string;
|
|
8
|
+
headers?: RequestHeaders;
|
|
9
|
+
params?: any;
|
|
10
|
+
};
|
|
11
|
+
tokensReqParams: {
|
|
12
|
+
url: string;
|
|
13
|
+
headers?: RequestHeaders;
|
|
14
|
+
params?: any;
|
|
15
|
+
};
|
|
16
|
+
tokensIntervalMs: number;
|
|
17
|
+
pricesCacheKey: string;
|
|
18
|
+
tokensAddrCacheKey: string;
|
|
19
|
+
tokensCacheKey: string;
|
|
20
|
+
pricesCacheTTLSecs: number;
|
|
21
|
+
tokensCacheTTLSecs: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type TokenDataMap = { [index: string]: BebopToken };
|
|
26
|
+
|
|
27
|
+
export type BebopToken = {
|
|
28
|
+
decimals: number;
|
|
29
|
+
contractAddress: string;
|
|
30
|
+
ticker: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type BebopTokensResponse = {
|
|
34
|
+
tokens: { [symbol: string]: BebopToken };
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type BebopLevel = [price: number, size: number];
|
|
38
|
+
|
|
39
|
+
export type BebopPair = {
|
|
40
|
+
bids: BebopLevel[];
|
|
41
|
+
asks: BebopLevel[];
|
|
42
|
+
last_update_ts: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type BebopPricingResponse = {
|
|
46
|
+
[pair: string]: BebopPair;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export interface BebopTx {
|
|
50
|
+
to: string;
|
|
51
|
+
value: string;
|
|
52
|
+
data: string;
|
|
53
|
+
from: string;
|
|
54
|
+
gas: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type BebopTokenAmount = {
|
|
58
|
+
amount: string;
|
|
59
|
+
priceUsd: number;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// For now nothing but we may have to add something
|
|
63
|
+
export type BebopData = {
|
|
64
|
+
expiry?: number;
|
|
65
|
+
buyTokens?: { [address: string]: BebopTokenAmount };
|
|
66
|
+
sellTokens?: { [address: string]: BebopTokenAmount };
|
|
67
|
+
tx?: BebopTx;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type DexParams = {
|
|
71
|
+
settlementAddress: string;
|
|
72
|
+
chainName: string;
|
|
73
|
+
middleTokens: string[];
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type RoutingInstruction = {
|
|
77
|
+
side: SwapSide; // Buy for bids, Sell for asks
|
|
78
|
+
book: BebopPair;
|
|
79
|
+
pair: string;
|
|
80
|
+
targetQuote: boolean;
|
|
81
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
|
|
3
|
+
// const pairValidator = joi.object({
|
|
4
|
+
// base: joi.string().min(1).required(),
|
|
5
|
+
// quote: joi.string().min(1).required(),
|
|
6
|
+
// liquidityUSD: joi.number().min(0).required(),
|
|
7
|
+
// baseAddress: joi.string().min(1).required(),
|
|
8
|
+
// quoteAddress: joi.string().min(1).required(),
|
|
9
|
+
// baseDecimals: joi.number().min(0).required(),
|
|
10
|
+
// quoteDecimals: joi.number().min(0).required(),
|
|
11
|
+
// });
|
|
12
|
+
|
|
13
|
+
// export const pairsResponseValidator = joi
|
|
14
|
+
// .object()
|
|
15
|
+
// .pattern(joi.string(), pairValidator);
|
|
16
|
+
|
|
17
|
+
const levelValidator = joi.array().items(joi.number()).length(2);
|
|
18
|
+
|
|
19
|
+
const pairValidator = joi.object({
|
|
20
|
+
bids: joi.array().items(levelValidator).required(),
|
|
21
|
+
asks: joi.array().items(levelValidator).required(),
|
|
22
|
+
last_update_ts: joi.number().min(0).required(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const pricesResponseValidator = joi
|
|
26
|
+
.object()
|
|
27
|
+
.pattern(joi.string(), pairValidator);
|
|
28
|
+
|
|
29
|
+
const tokenValidator = joi
|
|
30
|
+
.object({
|
|
31
|
+
ticker: joi.string().min(1).required(),
|
|
32
|
+
contractAddress: joi.string().min(1).required(),
|
|
33
|
+
decimals: joi.number().min(0).required(),
|
|
34
|
+
})
|
|
35
|
+
.unknown(true);
|
|
36
|
+
|
|
37
|
+
export const tokensResponseValidator = joi.object({
|
|
38
|
+
tokens: joi.object().pattern(joi.string(), tokenValidator),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const blacklistResponseValidator = joi.object({
|
|
42
|
+
blacklist: joi.array().items(joi.string().min(1)).required(),
|
|
43
|
+
});
|
package/src/dex/index.ts
CHANGED
|
@@ -76,6 +76,7 @@ import { AngleStakedStable } from './angle-staked-stable/angle-staked-stable';
|
|
|
76
76
|
import { QuickPerps } from './quick-perps/quick-perps';
|
|
77
77
|
import { NomiswapV2 } from './uniswap-v2/nomiswap-v2';
|
|
78
78
|
import { Dexalot } from './dexalot/dexalot';
|
|
79
|
+
import { Bebop } from './bebop/bebop';
|
|
79
80
|
import { Wombat } from './wombat/wombat';
|
|
80
81
|
import { Swell } from './swell/swell';
|
|
81
82
|
import { PharaohV1 } from './solidly/forks-override/pharaohV1';
|
|
@@ -110,6 +111,7 @@ const LegacyDexes = [
|
|
|
110
111
|
];
|
|
111
112
|
|
|
112
113
|
const Dexes = [
|
|
114
|
+
Bebop,
|
|
113
115
|
Dexalot,
|
|
114
116
|
CurveV1,
|
|
115
117
|
CurveFork,
|
|
@@ -26,8 +26,7 @@ export class WooFiV2PollingPool extends StatefulRpcPoller<
|
|
|
26
26
|
poolIdentifier: string,
|
|
27
27
|
dexHelper: IDexHelper,
|
|
28
28
|
protected config: DexParams,
|
|
29
|
-
|
|
30
|
-
protected tokens: Token[],
|
|
29
|
+
protected baseTokens: Token[],
|
|
31
30
|
) {
|
|
32
31
|
const callbacks = pollingManagerCbExtractor(
|
|
33
32
|
StatePollingManager.getInstance(dexHelper),
|
|
@@ -50,37 +49,66 @@ export class WooFiV2PollingPool extends StatefulRpcPoller<
|
|
|
50
49
|
decodeFunction: uint256ToBigInt,
|
|
51
50
|
},
|
|
52
51
|
] as MultiCallParams<MulticallResultOutputs>[]
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
52
|
+
)
|
|
53
|
+
.concat([
|
|
54
|
+
{
|
|
55
|
+
target: this.config.wooPPV2Address,
|
|
56
|
+
callData: ifaces.PPV2.encodeFunctionData('tokenInfos', [
|
|
57
|
+
this.config.quoteToken.address,
|
|
58
|
+
]),
|
|
59
|
+
decodeFunction: tokenInfoDecoder,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
target: this.config.wooPPV2Address,
|
|
63
|
+
callData: ifaces.PPV2.encodeFunctionData('decimalInfo', [
|
|
64
|
+
this.config.quoteToken.address,
|
|
65
|
+
]),
|
|
66
|
+
decodeFunction: decimalInfoDecoder,
|
|
67
|
+
},
|
|
68
|
+
])
|
|
69
|
+
.concat(
|
|
70
|
+
this.baseTokens
|
|
71
|
+
.map(t => [
|
|
72
|
+
{
|
|
73
|
+
target: this.config.wooPPV2Address,
|
|
74
|
+
callData: ifaces.PPV2.encodeFunctionData('tokenInfos', [
|
|
75
|
+
t.address,
|
|
76
|
+
]),
|
|
77
|
+
decodeFunction: tokenInfoDecoder,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
target: this.config.wooPPV2Address,
|
|
81
|
+
callData: ifaces.PPV2.encodeFunctionData('decimalInfo', [
|
|
82
|
+
t.address,
|
|
83
|
+
]),
|
|
84
|
+
decodeFunction: decimalInfoDecoder,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
target: this.config.wooOracleV2Address,
|
|
88
|
+
callData: ifaces.oracleV2.encodeFunctionData('state', [
|
|
89
|
+
t.address,
|
|
90
|
+
]),
|
|
91
|
+
decodeFunction: stateDecoder,
|
|
92
|
+
},
|
|
93
|
+
])
|
|
94
|
+
.flat(),
|
|
95
|
+
);
|
|
76
96
|
}
|
|
77
97
|
|
|
78
98
|
protected _parseStateFromMultiResults(
|
|
79
99
|
multiOutputs: MulticallResultOutputs[],
|
|
80
100
|
): PoolState {
|
|
81
|
-
const [
|
|
101
|
+
const [
|
|
102
|
+
isPaused,
|
|
103
|
+
oracleTimestamp,
|
|
104
|
+
quoteTokenInfo,
|
|
105
|
+
quoteTokenDecimals,
|
|
106
|
+
...remained
|
|
107
|
+
] = multiOutputs as [
|
|
82
108
|
boolean,
|
|
83
109
|
bigint,
|
|
110
|
+
TokenInfo,
|
|
111
|
+
DecimalInfo,
|
|
84
112
|
...MulticallResultOutputs[],
|
|
85
113
|
];
|
|
86
114
|
|
|
@@ -88,13 +116,16 @@ export class WooFiV2PollingPool extends StatefulRpcPoller<
|
|
|
88
116
|
const decimals: Record<string, DecimalInfo> = {};
|
|
89
117
|
const tokenStates: Record<string, TokenState> = {};
|
|
90
118
|
|
|
119
|
+
tokenInfos[this.config.quoteToken.address] = quoteTokenInfo;
|
|
120
|
+
decimals[this.config.quoteToken.address] = quoteTokenDecimals;
|
|
121
|
+
|
|
91
122
|
_.chunk(remained, 3).forEach((chunk, i) => {
|
|
92
123
|
const [tokenInfo, decimalInfo, tokenState] = chunk as [
|
|
93
124
|
TokenInfo,
|
|
94
125
|
DecimalInfo,
|
|
95
126
|
TokenState,
|
|
96
127
|
];
|
|
97
|
-
const token = this.
|
|
128
|
+
const token = this.baseTokens[i];
|
|
98
129
|
|
|
99
130
|
tokenInfos[token.address] = tokenInfo;
|
|
100
131
|
decimals[token.address] = decimalInfo;
|
|
@@ -27,7 +27,6 @@ import { ethers } from 'ethers';
|
|
|
27
27
|
import { addressDecode } from '../../lib/decoders';
|
|
28
28
|
import { ifaces } from './utils';
|
|
29
29
|
import { StatePollingManager } from '../../lib/stateful-rpc-poller/state-polling-manager';
|
|
30
|
-
import { solidityPack } from 'ethers/lib/utils';
|
|
31
30
|
import { extractReturnAmountPosition } from '../../executor/utils';
|
|
32
31
|
|
|
33
32
|
export class WooFiV2 extends SimpleExchange implements IDex<WooFiV2Data> {
|
|
@@ -521,7 +520,7 @@ export class WooFiV2 extends SimpleExchange implements IDex<WooFiV2Data> {
|
|
|
521
520
|
this.getIdentifier(),
|
|
522
521
|
this.dexHelper,
|
|
523
522
|
this.config,
|
|
524
|
-
|
|
523
|
+
this.baseTokens,
|
|
525
524
|
);
|
|
526
525
|
|
|
527
526
|
this.pollingManager.initializeAllPendingPools();
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Logger } from 'log4js';
|
|
2
|
+
import { RequestConfig, Response } from '../../dex-helper/irequest-wrapper';
|
|
3
|
+
import {
|
|
4
|
+
connection as WebSocketConnection,
|
|
5
|
+
client as WebSocketClient,
|
|
6
|
+
} from 'websocket';
|
|
7
|
+
|
|
8
|
+
export class SkippingRequest {
|
|
9
|
+
constructor(public message = '') {}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type RequestInfo<T> = {
|
|
13
|
+
requestFunc?: (
|
|
14
|
+
options: RequestConfig,
|
|
15
|
+
) => Promise<Response<T> | SkippingRequest>;
|
|
16
|
+
requestOptions: RequestConfig;
|
|
17
|
+
caster: (data: unknown) => T;
|
|
18
|
+
authenticate?: (options: RequestConfig) => RequestConfig;
|
|
19
|
+
excludedFieldsCaching?: string[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type RequestInfoWithHandler<T> = {
|
|
23
|
+
info: RequestInfo<T>;
|
|
24
|
+
handler: (data: T) => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class WebSocketFetcher<T> {
|
|
28
|
+
private requests: RequestInfoWithHandler<T>;
|
|
29
|
+
public lastFetchSucceeded: boolean = false;
|
|
30
|
+
private stop: boolean = true;
|
|
31
|
+
private ws: WebSocketClient = new WebSocketClient();
|
|
32
|
+
private connection: WebSocketConnection | null = null;
|
|
33
|
+
|
|
34
|
+
constructor(requestsInfo: RequestInfoWithHandler<T>, private logger: Logger) {
|
|
35
|
+
this.requests = requestsInfo;
|
|
36
|
+
this.ws.on('connect', this.connected.bind(this));
|
|
37
|
+
this.ws.on('connectFailed', this.connectFailed.bind(this));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private connected(connection: WebSocketConnection) {
|
|
41
|
+
this.connection = connection;
|
|
42
|
+
this.logger.info(`Connected to ${this.requests.info.requestOptions.url}`);
|
|
43
|
+
this.connection.on('error', this.onError.bind(this));
|
|
44
|
+
this.connection.on('close', this.onClose.bind(this));
|
|
45
|
+
this.connection.on('message', this.onMessage.bind(this));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private connectFailed(error: any) {
|
|
49
|
+
this.logger.error(`Connect Error: ${error.toString()}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private onClose() {
|
|
53
|
+
this.logger.info(`Connection closed`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private onError(error: any) {
|
|
57
|
+
this.logger.error(`Connection Error: ${error.toString()}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private onMessage(message: any) {
|
|
61
|
+
if (message.type === 'utf8') {
|
|
62
|
+
const response = JSON.parse(message.utf8Data) as Response<T>;
|
|
63
|
+
const reqInfo = this.requests;
|
|
64
|
+
const info = reqInfo.info;
|
|
65
|
+
const options = reqInfo.info.requestOptions;
|
|
66
|
+
this.logger.debug(`(${options.url}) received new data`);
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const parsedData = info.caster(response);
|
|
70
|
+
reqInfo.handler(parsedData);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
this.logger.info(e);
|
|
73
|
+
this.logger.info(
|
|
74
|
+
`(${options.url}) received incorrect data ${JSON.stringify(
|
|
75
|
+
response,
|
|
76
|
+
).replace(/(?:\r\n|\r|\n)/g, ' ')}`,
|
|
77
|
+
e,
|
|
78
|
+
);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private connect() {
|
|
85
|
+
const authorization =
|
|
86
|
+
this.requests.info.requestOptions.headers!.authorization;
|
|
87
|
+
const name = this.requests.info.requestOptions.headers!.name;
|
|
88
|
+
if (typeof authorization !== 'string') {
|
|
89
|
+
throw new Error('Authorization header is not a string');
|
|
90
|
+
}
|
|
91
|
+
if (typeof name !== 'string') {
|
|
92
|
+
throw new Error('Name header is not a string');
|
|
93
|
+
}
|
|
94
|
+
this.ws.connect(
|
|
95
|
+
this.requests.info.requestOptions.url!,
|
|
96
|
+
undefined,
|
|
97
|
+
undefined,
|
|
98
|
+
{
|
|
99
|
+
Authorization: authorization,
|
|
100
|
+
name: name,
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
startPolling(): void {
|
|
106
|
+
this.stop = false;
|
|
107
|
+
this.connect();
|
|
108
|
+
this.logger.info(
|
|
109
|
+
`Connection started for ${this.requests.info.requestOptions.url}`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
stopPolling() {
|
|
114
|
+
if (this.connection) {
|
|
115
|
+
this.connection.close();
|
|
116
|
+
}
|
|
117
|
+
this.stop = true;
|
|
118
|
+
this.logger.info(
|
|
119
|
+
`Connection stopped for ${this.requests.info.requestOptions.url}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
isPolling(): boolean {
|
|
124
|
+
return !this.stop;
|
|
125
|
+
}
|
|
126
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -304,6 +304,7 @@ export type Config = {
|
|
|
304
304
|
uniswapV3EventLoggingSampleRate?: number;
|
|
305
305
|
swaapV2AuthToken?: string;
|
|
306
306
|
dexalotAuthToken?: string;
|
|
307
|
+
bebopAuthToken?: string;
|
|
307
308
|
idleDaoAuthToken?: string;
|
|
308
309
|
forceRpcFallbackDexs: string[];
|
|
309
310
|
apiKeyTheGraph: string;
|