@paraswap/dex-lib 2.34.0 → 2.35.0
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/api3-proxy.json +46 -0
- package/build/abi/api3-server-v1.json +463 -0
- package/build/abi/quick-perps/fast-price-events.json +70 -0
- package/build/abi/quick-perps/fast-price-feed.json +741 -0
- package/build/abi/quick-perps/reader.json +313 -0
- package/build/abi/quick-perps/vault-price-feed.json +323 -0
- package/build/abi/quick-perps/vault.json +1953 -0
- package/build/composed-event-subscriber.js +8 -2
- package/build/composed-event-subscriber.js.map +1 -1
- package/build/config.js +2 -2
- package/build/dex/index.js +2 -0
- package/build/dex/index.js.map +1 -1
- package/build/dex/quick-perps/config.d.ts +11 -0
- package/build/dex/quick-perps/config.js +27 -0
- package/build/dex/quick-perps/config.js.map +1 -0
- package/build/dex/quick-perps/fast-price-feed.d.ts +26 -0
- package/build/dex/quick-perps/fast-price-feed.js +176 -0
- package/build/dex/quick-perps/fast-price-feed.js.map +1 -0
- package/build/dex/quick-perps/pool.d.ts +21 -0
- package/build/dex/quick-perps/pool.js +210 -0
- package/build/dex/quick-perps/pool.js.map +1 -0
- package/build/dex/quick-perps/quick-perps.d.ts +52 -0
- package/build/dex/quick-perps/quick-perps.js +205 -0
- package/build/dex/quick-perps/quick-perps.js.map +1 -0
- package/build/dex/quick-perps/types.d.ts +98 -0
- package/build/dex/quick-perps/types.js +3 -0
- package/build/dex/quick-perps/types.js.map +1 -0
- package/build/dex/quick-perps/usdq.d.ts +15 -0
- package/build/dex/quick-perps/usdq.js +61 -0
- package/build/dex/quick-perps/usdq.js.map +1 -0
- package/build/dex/quick-perps/vault-price-feed.d.ts +43 -0
- package/build/dex/quick-perps/vault-price-feed.js +194 -0
- package/build/dex/quick-perps/vault-price-feed.js.map +1 -0
- package/build/dex/quick-perps/vault-utils.d.ts +8 -0
- package/build/dex/quick-perps/vault-utils.js +41 -0
- package/build/dex/quick-perps/vault-utils.js.map +1 -0
- package/build/dex/quick-perps/vault.d.ts +46 -0
- package/build/dex/quick-perps/vault.js +166 -0
- package/build/dex/quick-perps/vault.js.map +1 -0
- package/build/lib/api3-feed.d.ts +26 -0
- package/build/lib/api3-feed.js +82 -0
- package/build/lib/api3-feed.js.map +1 -0
- package/package.json +1 -1
- package/src/abi/api3-proxy.json +46 -0
- package/src/abi/api3-server-v1.json +463 -0
- package/src/abi/quick-perps/fast-price-events.json +70 -0
- package/src/abi/quick-perps/fast-price-feed.json +741 -0
- package/src/abi/quick-perps/reader.json +313 -0
- package/src/abi/quick-perps/vault-price-feed.json +323 -0
- package/src/abi/quick-perps/vault.json +1953 -0
- package/src/composed-event-subscriber.ts +16 -11
- package/src/config.ts +2 -2
- package/src/dex/index.ts +2 -0
- package/src/dex/quick-perps/config.ts +31 -0
- package/src/dex/quick-perps/fast-price-feed.ts +279 -0
- package/src/dex/quick-perps/pool.ts +372 -0
- package/src/dex/quick-perps/quick-perps-e2e.test.ts +65 -0
- package/src/dex/quick-perps/quick-perps-events.test.ts +101 -0
- package/src/dex/quick-perps/quick-perps-integration.test.ts +153 -0
- package/src/dex/quick-perps/quick-perps.ts +292 -0
- package/src/dex/quick-perps/types.ts +97 -0
- package/src/dex/quick-perps/usdq.ts +83 -0
- package/src/dex/quick-perps/vault-price-feed.ts +322 -0
- package/src/dex/quick-perps/vault-utils.ts +53 -0
- package/src/dex/quick-perps/vault.ts +290 -0
- package/src/lib/api3-feed.ts +140 -0
- package/tests/constants-e2e.ts +29 -0
- package/tests/tenderly-simulation.ts +46 -2
- package/tests/utils-e2e.ts +18 -10
|
@@ -110,17 +110,22 @@ export abstract class ComposedEventSubscriber<
|
|
|
110
110
|
.call({}, blockNumber)
|
|
111
111
|
).returnData;
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
try {
|
|
114
|
+
const stateParts = await Promise.all(
|
|
115
|
+
this.parts.map((p, i) =>
|
|
116
|
+
p.generateState(
|
|
117
|
+
returnData.slice(...this.multiCallSlices[i]),
|
|
118
|
+
blockNumber,
|
|
119
|
+
),
|
|
118
120
|
),
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
121
|
+
);
|
|
122
|
+
return this.parts.reduce(
|
|
123
|
+
(acc, p, i) => p.lens.set(stateParts[i])(acc),
|
|
124
|
+
this.blankState,
|
|
125
|
+
);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
this.logger.error(`Error generating state: ${e}`);
|
|
128
|
+
throw e;
|
|
129
|
+
}
|
|
125
130
|
}
|
|
126
131
|
}
|
package/src/config.ts
CHANGED
|
@@ -332,8 +332,8 @@ const baseConfigs: { [network: number]: BaseConfig } = {
|
|
|
332
332
|
multicallV2Address: '0x6cA478C852DfA8941FC819fDf248606eA04780B6',
|
|
333
333
|
privateHttpProvider: process.env.HTTP_PROVIDER_1101,
|
|
334
334
|
adapterAddresses: {
|
|
335
|
-
PolygonZkEvmAdapter01: '
|
|
336
|
-
PolygonZkEvmBuyAdapter: '
|
|
335
|
+
PolygonZkEvmAdapter01: '0xd63B7691dD98fa89A2ea5e1604700489c585aa7B',
|
|
336
|
+
PolygonZkEvmBuyAdapter: '0xe2137168CdA486a2555E16c597905854C84F9127',
|
|
337
337
|
},
|
|
338
338
|
|
|
339
339
|
rpcPollingMaxAllowedStateDelayInBlocks: 0,
|
package/src/dex/index.ts
CHANGED
|
@@ -73,6 +73,7 @@ import { SpiritSwapV3 } from './quickswap/spiritswap-v3';
|
|
|
73
73
|
import { TraderJoeV21 } from './trader-joe-v2.1';
|
|
74
74
|
import { PancakeswapV3 } from './pancakeswap-v3/pancakeswap-v3';
|
|
75
75
|
import { Algebra } from './algebra/algebra';
|
|
76
|
+
import { QuickPerps } from './quick-perps/quick-perps';
|
|
76
77
|
import { NomiswapV2 } from './uniswap-v2/nomiswap-v2';
|
|
77
78
|
|
|
78
79
|
const LegacyDexes = [
|
|
@@ -144,6 +145,7 @@ const Dexes = [
|
|
|
144
145
|
MaverickV1,
|
|
145
146
|
Camelot,
|
|
146
147
|
SwaapV2,
|
|
148
|
+
QuickPerps,
|
|
147
149
|
NomiswapV2,
|
|
148
150
|
];
|
|
149
151
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DexParams } from './types';
|
|
2
|
+
import { DexConfigMap } from '../../types';
|
|
3
|
+
import { Network, SwapSide } from '../../constants';
|
|
4
|
+
|
|
5
|
+
export const QuickPerpsConfig: DexConfigMap<DexParams> = {
|
|
6
|
+
QuickPerps: {
|
|
7
|
+
[Network.ZKEVM]: {
|
|
8
|
+
vault: '0x99B31498B0a1Dae01fc3433e3Cb60F095340935C',
|
|
9
|
+
reader: '0xf1CFB75854DE535475B88Bb6FBad317eea98c0F9',
|
|
10
|
+
priceFeed: '0x5b1F500134bdD7f4359F5B2adC65f839737290f4',
|
|
11
|
+
fastPriceFeed: '0x73903fEc691a80Ec47bc830bf3F0baD127A06e30',
|
|
12
|
+
fastPriceEvents: '0x08bC8ef0b71238055f9Ee6BBc90869D8d0DBdCCa',
|
|
13
|
+
usdq: '0x48aC594dd00c4aAcF40f83337fc6dA31F9F439A7',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Adapters: {
|
|
19
|
+
[chainId: number]: {
|
|
20
|
+
[side: string]: { name: string; index: number }[] | null;
|
|
21
|
+
};
|
|
22
|
+
} = {
|
|
23
|
+
[Network.ZKEVM]: {
|
|
24
|
+
[SwapSide.SELL]: [
|
|
25
|
+
{
|
|
26
|
+
name: 'PolygonZkEvmAdapter01',
|
|
27
|
+
index: 2,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { Interface } from '@ethersproject/abi';
|
|
3
|
+
import { DeepReadonly } from 'ts-essentials';
|
|
4
|
+
import { PartialEventSubscriber } from '../../composed-event-subscriber';
|
|
5
|
+
import {
|
|
6
|
+
Address,
|
|
7
|
+
MultiCallInput,
|
|
8
|
+
MultiCallOutput,
|
|
9
|
+
Logger,
|
|
10
|
+
Log,
|
|
11
|
+
BlockHeader,
|
|
12
|
+
} from '../../types';
|
|
13
|
+
import { FastPriceFeedConfig, FastPriceFeedState } from './types';
|
|
14
|
+
import FastPriceFeedAbi from '../../abi/quick-perps/fast-price-feed.json';
|
|
15
|
+
import FastPriceEventsAbi from '../../abi/quick-perps/fast-price-events.json';
|
|
16
|
+
import { Lens } from '../../lens';
|
|
17
|
+
|
|
18
|
+
export class FastPriceFeed<State> extends PartialEventSubscriber<
|
|
19
|
+
State,
|
|
20
|
+
FastPriceFeedState
|
|
21
|
+
> {
|
|
22
|
+
static readonly interface = new Interface(FastPriceFeedAbi);
|
|
23
|
+
static readonly fastPriceEventsInterface = new Interface(FastPriceEventsAbi);
|
|
24
|
+
|
|
25
|
+
BASIS_POINTS_DIVISOR = 10000n;
|
|
26
|
+
protected priceDuration: number;
|
|
27
|
+
protected maxDeviationBasisPoints: bigint;
|
|
28
|
+
protected favorFastPrice: Record<string, boolean>;
|
|
29
|
+
private spreadBasisPointsIfInactive: bigint;
|
|
30
|
+
private spreadBasisPointsIfChainError: bigint;
|
|
31
|
+
private maxPriceUpdateDelay: number;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
private fastPriceFeedAddress: Address,
|
|
35
|
+
fastPriceEventsAddress: Address,
|
|
36
|
+
private tokenAddresses: Address[],
|
|
37
|
+
config: FastPriceFeedConfig,
|
|
38
|
+
lens: Lens<DeepReadonly<State>, DeepReadonly<FastPriceFeedState>>,
|
|
39
|
+
logger: Logger,
|
|
40
|
+
) {
|
|
41
|
+
super([fastPriceEventsAddress], lens, logger);
|
|
42
|
+
this.priceDuration = config.priceDuration;
|
|
43
|
+
this.maxDeviationBasisPoints = config.maxDeviationBasisPoints;
|
|
44
|
+
this.favorFastPrice = config.favorFastPrice;
|
|
45
|
+
this.spreadBasisPointsIfInactive = config.spreadBasisPointsIfInactive;
|
|
46
|
+
this.spreadBasisPointsIfChainError = config.spreadBasisPointsIfChainError;
|
|
47
|
+
this.maxPriceUpdateDelay = config.maxPriceUpdateDelay;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public processLog(
|
|
51
|
+
state: DeepReadonly<FastPriceFeedState>,
|
|
52
|
+
log: Readonly<Log>,
|
|
53
|
+
blockHeader: Readonly<BlockHeader>,
|
|
54
|
+
): DeepReadonly<FastPriceFeedState> | null {
|
|
55
|
+
try {
|
|
56
|
+
const parsed = FastPriceFeed.fastPriceEventsInterface.parseLog(log);
|
|
57
|
+
switch (parsed.name) {
|
|
58
|
+
case 'PriceUpdate': {
|
|
59
|
+
const _state: FastPriceFeedState = _.cloneDeep(state);
|
|
60
|
+
_state.lastUpdatedAt =
|
|
61
|
+
typeof blockHeader.timestamp === 'string'
|
|
62
|
+
? parseInt(blockHeader.timestamp)
|
|
63
|
+
: blockHeader.timestamp;
|
|
64
|
+
const tokenAddress = parsed.args.token.toLowerCase();
|
|
65
|
+
if (tokenAddress in state.prices)
|
|
66
|
+
_state.prices[tokenAddress] = BigInt(parsed.args.price.toString());
|
|
67
|
+
return _state;
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
this.logger.error('Failed to parse log', e);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getPrice(
|
|
79
|
+
_state: DeepReadonly<State>,
|
|
80
|
+
_token: Address,
|
|
81
|
+
_refPrice: bigint,
|
|
82
|
+
_maximize: boolean,
|
|
83
|
+
) {
|
|
84
|
+
const state = this.lens.get()(_state);
|
|
85
|
+
|
|
86
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
87
|
+
|
|
88
|
+
if (timestamp > state.lastUpdatedAt + this.maxPriceUpdateDelay) {
|
|
89
|
+
if (_maximize) {
|
|
90
|
+
return (
|
|
91
|
+
(_refPrice *
|
|
92
|
+
(this.BASIS_POINTS_DIVISOR + this.spreadBasisPointsIfChainError)) /
|
|
93
|
+
this.BASIS_POINTS_DIVISOR
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
(_refPrice *
|
|
99
|
+
(this.BASIS_POINTS_DIVISOR - this.spreadBasisPointsIfChainError)) /
|
|
100
|
+
this.BASIS_POINTS_DIVISOR
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (timestamp > state.lastUpdatedAt + this.priceDuration) {
|
|
105
|
+
if (_maximize) {
|
|
106
|
+
return (
|
|
107
|
+
(_refPrice *
|
|
108
|
+
(this.BASIS_POINTS_DIVISOR + this.spreadBasisPointsIfInactive)) /
|
|
109
|
+
this.BASIS_POINTS_DIVISOR
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
(_refPrice *
|
|
115
|
+
(this.BASIS_POINTS_DIVISOR - this.spreadBasisPointsIfInactive)) /
|
|
116
|
+
this.BASIS_POINTS_DIVISOR
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const fastPrice = state.prices[_token];
|
|
121
|
+
if (fastPrice === 0n) return _refPrice;
|
|
122
|
+
|
|
123
|
+
let diffBasisPoints =
|
|
124
|
+
_refPrice > fastPrice ? _refPrice - fastPrice : fastPrice - _refPrice;
|
|
125
|
+
diffBasisPoints = (diffBasisPoints * this.BASIS_POINTS_DIVISOR) / _refPrice;
|
|
126
|
+
|
|
127
|
+
// create a spread between the _refPrice and the fastPrice if the maxDeviationBasisPoints is exceeded
|
|
128
|
+
// or if watchers have flagged an issue with the fast price
|
|
129
|
+
const hasSpread =
|
|
130
|
+
!this.favorFastPrice[_token] ||
|
|
131
|
+
diffBasisPoints > this.maxDeviationBasisPoints;
|
|
132
|
+
|
|
133
|
+
if (hasSpread) {
|
|
134
|
+
// return the higher of the two prices
|
|
135
|
+
if (_maximize) {
|
|
136
|
+
return _refPrice > fastPrice ? _refPrice : fastPrice;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// return the lower of the two prices
|
|
140
|
+
return _refPrice < fastPrice ? _refPrice : fastPrice;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return fastPrice;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static getConfigMulticallInputs(
|
|
147
|
+
fastPriceFeedAddress: Address,
|
|
148
|
+
tokenAddresses: Address[],
|
|
149
|
+
): MultiCallInput[] {
|
|
150
|
+
return [
|
|
151
|
+
{
|
|
152
|
+
target: fastPriceFeedAddress,
|
|
153
|
+
callData: FastPriceFeed.interface.encodeFunctionData('priceDuration'),
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
target: fastPriceFeedAddress,
|
|
157
|
+
callData: FastPriceFeed.interface.encodeFunctionData(
|
|
158
|
+
'maxDeviationBasisPoints',
|
|
159
|
+
),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
target: fastPriceFeedAddress,
|
|
163
|
+
callData: FastPriceFeed.interface.encodeFunctionData(
|
|
164
|
+
'spreadBasisPointsIfInactive',
|
|
165
|
+
),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
target: fastPriceFeedAddress,
|
|
169
|
+
callData: FastPriceFeed.interface.encodeFunctionData(
|
|
170
|
+
'spreadBasisPointsIfChainError',
|
|
171
|
+
),
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
target: fastPriceFeedAddress,
|
|
175
|
+
callData: FastPriceFeed.interface.encodeFunctionData(
|
|
176
|
+
'maxPriceUpdateDelay',
|
|
177
|
+
),
|
|
178
|
+
},
|
|
179
|
+
...tokenAddresses.map(t => ({
|
|
180
|
+
target: fastPriceFeedAddress,
|
|
181
|
+
callData: FastPriceFeed.interface.encodeFunctionData('favorFastPrice', [
|
|
182
|
+
t,
|
|
183
|
+
]),
|
|
184
|
+
})),
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static getConfig(
|
|
189
|
+
multicallOutputs: MultiCallOutput[],
|
|
190
|
+
tokenAddresses: Address[],
|
|
191
|
+
): FastPriceFeedConfig {
|
|
192
|
+
return {
|
|
193
|
+
priceDuration: parseInt(
|
|
194
|
+
FastPriceFeed.interface
|
|
195
|
+
.decodeFunctionResult('priceDuration', multicallOutputs[0])[0]
|
|
196
|
+
.toString(),
|
|
197
|
+
),
|
|
198
|
+
maxDeviationBasisPoints: BigInt(
|
|
199
|
+
FastPriceFeed.interface
|
|
200
|
+
.decodeFunctionResult(
|
|
201
|
+
'maxDeviationBasisPoints',
|
|
202
|
+
multicallOutputs[1],
|
|
203
|
+
)[0]
|
|
204
|
+
.toString(),
|
|
205
|
+
),
|
|
206
|
+
spreadBasisPointsIfInactive: BigInt(
|
|
207
|
+
FastPriceFeed.interface
|
|
208
|
+
.decodeFunctionResult(
|
|
209
|
+
'spreadBasisPointsIfInactive',
|
|
210
|
+
multicallOutputs[2],
|
|
211
|
+
)[0]
|
|
212
|
+
.toString(),
|
|
213
|
+
),
|
|
214
|
+
spreadBasisPointsIfChainError: BigInt(
|
|
215
|
+
FastPriceFeed.interface
|
|
216
|
+
.decodeFunctionResult(
|
|
217
|
+
'spreadBasisPointsIfChainError',
|
|
218
|
+
multicallOutputs[3],
|
|
219
|
+
)[0]
|
|
220
|
+
.toString(),
|
|
221
|
+
),
|
|
222
|
+
maxPriceUpdateDelay: parseInt(
|
|
223
|
+
FastPriceFeed.interface
|
|
224
|
+
.decodeFunctionResult('maxPriceUpdateDelay', multicallOutputs[4])[0]
|
|
225
|
+
.toString(),
|
|
226
|
+
),
|
|
227
|
+
favorFastPrice: multicallOutputs
|
|
228
|
+
.slice(5)
|
|
229
|
+
.reduce<Record<string, boolean>>((acc, curr, i) => {
|
|
230
|
+
acc[tokenAddresses[i]] = FastPriceFeed.interface.decodeFunctionResult(
|
|
231
|
+
'favorFastPrice',
|
|
232
|
+
curr,
|
|
233
|
+
)[0];
|
|
234
|
+
return acc;
|
|
235
|
+
}, {}),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public getGenerateStateMultiCallInputs(): MultiCallInput[] {
|
|
240
|
+
const pricesEntries = this.tokenAddresses.map((t: Address) => ({
|
|
241
|
+
target: this.fastPriceFeedAddress,
|
|
242
|
+
callData: FastPriceFeed.interface.encodeFunctionData('prices', [t]),
|
|
243
|
+
}));
|
|
244
|
+
return [
|
|
245
|
+
...pricesEntries,
|
|
246
|
+
{
|
|
247
|
+
target: this.fastPriceFeedAddress,
|
|
248
|
+
callData: FastPriceFeed.interface.encodeFunctionData('lastUpdatedAt'),
|
|
249
|
+
},
|
|
250
|
+
];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
public generateState(
|
|
254
|
+
multicallOutputs: MultiCallOutput[],
|
|
255
|
+
blockNumber?: number | 'latest',
|
|
256
|
+
): DeepReadonly<FastPriceFeedState> {
|
|
257
|
+
let fastPriceFeedState: FastPriceFeedState = {
|
|
258
|
+
prices: {},
|
|
259
|
+
lastUpdatedAt: 0,
|
|
260
|
+
};
|
|
261
|
+
this.tokenAddresses.forEach(
|
|
262
|
+
(t: Address, i: number) =>
|
|
263
|
+
(fastPriceFeedState.prices[t] = BigInt(
|
|
264
|
+
FastPriceFeed.interface
|
|
265
|
+
.decodeFunctionResult('prices', multicallOutputs[i])[0]
|
|
266
|
+
.toString(),
|
|
267
|
+
)),
|
|
268
|
+
);
|
|
269
|
+
fastPriceFeedState.lastUpdatedAt = parseInt(
|
|
270
|
+
FastPriceFeed.interface
|
|
271
|
+
.decodeFunctionResult(
|
|
272
|
+
'lastUpdatedAt',
|
|
273
|
+
multicallOutputs[this.tokenAddresses.length],
|
|
274
|
+
)[0]
|
|
275
|
+
.toString(),
|
|
276
|
+
);
|
|
277
|
+
return fastPriceFeedState;
|
|
278
|
+
}
|
|
279
|
+
}
|