@paraswap/dex-lib 3.4.2-balancer-v2-single-swap.0 → 3.4.2
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/README.md +377 -377
- package/build/config.js +9 -5
- package/build/config.js.map +1 -1
- package/build/dex/algebra/algebra.js +25 -25
- package/build/dex/balancer-v1/balancer-v1.js +34 -34
- package/build/dex/balancer-v2/balancer-v2.d.ts +1 -1
- package/build/dex/balancer-v2/balancer-v2.js +65 -78
- package/build/dex/balancer-v2/balancer-v2.js.map +1 -1
- package/build/dex/camelot/camelot.js +27 -27
- package/build/dex/kyberdmm/kyberdmm.js +27 -27
- package/build/dex/pancakeswap-v3/pancakeswap-v3.js +25 -25
- package/build/dex/solidly/solidly.js +27 -27
- package/build/dex/solidly-v3/solidly-v3.js +25 -25
- package/build/dex/swaap-v2/config.js +15 -0
- package/build/dex/swaap-v2/config.js.map +1 -1
- package/build/dex/uniswap-v2/uniswap-v2.js +26 -26
- package/build/dex/uniswap-v3/uniswap-v3.js +25 -25
- package/funding.json +5 -5
- package/package.json +1 -1
- package/src/config.ts +500 -496
- package/src/constants.ts +67 -67
- package/src/dex/aave-v2/aave-v2.ts +409 -409
- package/src/dex/aave-v3/aave-v3.ts +320 -320
- package/src/dex/algebra/algebra.ts +1180 -1180
- package/src/dex/angle-staked-stable/angle-staked-stable.ts +347 -347
- package/src/dex/augustus-rfq.ts +180 -180
- package/src/dex/bProtocol/bProtocol.ts +108 -108
- package/src/dex/balancer-v1/balancer-v1.ts +572 -572
- package/src/dex/balancer-v2/balancer-v2-e2e.test.ts +1699 -1699
- package/src/dex/balancer-v2/balancer-v2.ts +1669 -1701
- package/src/dex/bancor/bancor.ts +128 -128
- package/src/dex/camelot/camelot.ts +873 -873
- package/src/dex/compound/compound.ts +107 -107
- package/src/dex/curve-v1/config.ts +1179 -1179
- package/src/dex/curve-v1/curve-v1-e2e.test.ts +507 -507
- package/src/dex/curve-v1/curve-v1.ts +1315 -1315
- package/src/dex/curve-v1-factory/config.ts +1018 -1018
- package/src/dex/curve-v1-factory/curve-v1-factory.ts +1288 -1288
- package/src/dex/curve-v2/curve-v2.ts +440 -440
- package/src/dex/dexalot/dexalot.ts +1100 -1100
- package/src/dex/dodo-v1/dodo-v1.ts +132 -132
- package/src/dex/dodo-v2.ts +266 -266
- package/src/dex/etherfi.ts +239 -239
- package/src/dex/generic-rfq/generic-rfq.ts +431 -431
- package/src/dex/gmx/gmx.ts +321 -321
- package/src/dex/hashflow/hashflow.ts +1135 -1135
- package/src/dex/idex.ts +254 -254
- package/src/dex/index.ts +357 -357
- package/src/dex/jarvis-v6/jarvis-v6.ts +509 -509
- package/src/dex/jarvis.ts +262 -262
- package/src/dex/kyberdmm/kyberdmm.ts +649 -649
- package/src/dex/lido/lido.ts +110 -110
- package/src/dex/maker-psm/maker-psm.ts +592 -592
- package/src/dex/maverick-v1/maverick-v1.ts +537 -537
- package/src/dex/nerve/config.ts +635 -635
- package/src/dex/nerve/nerve-e2e.test.ts +731 -731
- package/src/dex/nerve/nerve-events.test.ts +911 -911
- package/src/dex/nerve/nerve.ts +467 -467
- package/src/dex/onebit/onebit.ts +113 -113
- package/src/dex/pancakeswap-v3/pancakeswap-v3.ts +1150 -1150
- package/src/dex/paraswap-limit-orders/config.ts +60 -60
- package/src/dex/paraswap-limit-orders/paraswap-limit-orders-e2e.test.ts +137 -137
- package/src/dex/paraswap-limit-orders/paraswap-limit-orders-integration.test.ts +328 -328
- package/src/dex/paraswap-limit-orders/paraswap-limit-orders.ts +631 -631
- package/src/dex/polygon-migrator/polygon-migrator.ts +194 -194
- package/src/dex/quick-perps/quick-perps.ts +337 -337
- package/src/dex/quickswap/config.ts +16 -16
- package/src/dex/quickswap/quickswap-e2e.test.ts +384 -384
- package/src/dex/smoothy/smoothy.ts +110 -110
- package/src/dex/solidly/config.ts +225 -225
- package/src/dex/solidly/solidly-e2e.test.ts +1421 -1421
- package/src/dex/solidly/solidly-integration.test.ts +1753 -1753
- package/src/dex/solidly/solidly.ts +687 -687
- package/src/dex/solidly-v3/solidly-v3.ts +968 -968
- package/src/dex/spark/spark.ts +284 -284
- package/src/dex/stable-pool/stable-pool.ts +129 -129
- package/src/dex/swaap-v2/config.ts +15 -0
- package/src/dex/swaap-v2/swaap-v2-e2e.test.ts +233 -17
- package/src/dex/swaap-v2/swaap-v2-integration.test.ts +1 -1
- package/src/dex/swaap-v2/swaap-v2.ts +1056 -1056
- package/src/dex/swell/swell.ts +312 -312
- package/src/dex/synthetix/synthetix.ts +420 -420
- package/src/dex/trader-joe-v2.1/trader-joe-v2.1.ts +180 -180
- package/src/dex/uniswap-v2/config.ts +637 -637
- package/src/dex/uniswap-v2/constants.ts +58 -58
- package/src/dex/uniswap-v2/uniswap-v2-e2e-avalanche.test.ts +1257 -1257
- package/src/dex/uniswap-v2/uniswap-v2-e2e-base.test.ts +42 -42
- package/src/dex/uniswap-v2/uniswap-v2-e2e-bsc.test.ts +1295 -1295
- package/src/dex/uniswap-v2/uniswap-v2-e2e-mainnet.test.ts +1834 -1834
- package/src/dex/uniswap-v2/uniswap-v2-e2e-polygon.test.ts +871 -871
- package/src/dex/uniswap-v2/uniswap-v2.ts +1117 -1117
- package/src/dex/uniswap-v3/uniswap-v3.ts +1501 -1501
- package/src/dex/uniswap-v3.ts +242 -242
- package/src/dex/weth/config.ts +73 -73
- package/src/dex/weth/weth.ts +230 -230
- package/src/dex/wombat/wombat.ts +467 -467
- package/src/dex/woo-fi-v2/woo-fi-v2.ts +529 -529
- package/src/dex/wsteth/wsteth.ts +304 -304
- package/src/dex/zerox/index.ts +328 -328
- package/src/executor/Executor01BytecodeBuilder.ts +474 -474
- package/src/executor/Executor02BytecodeBuilder.ts +1392 -1392
- package/src/executor/ExecutorBytecodeBuilder.ts +390 -390
- package/src/executor/ExecutorDetector.ts +131 -131
- package/src/executor/constants.ts +66 -66
- package/src/executor/executor01-bytecode-builder-e2e.test.ts +1478 -1478
- package/src/executor/utils.ts +62 -62
- package/src/router/simpleswap.ts +366 -366
- package/src/types.ts +342 -342
- package/tests/constants-e2e.ts +1632 -1622
- package/tests/generate-new-limit-order.ts +107 -107
|
@@ -1,631 +1,631 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
import { Interface } from '@ethersproject/abi';
|
|
3
|
-
import {
|
|
4
|
-
Token,
|
|
5
|
-
Address,
|
|
6
|
-
ExchangePrices,
|
|
7
|
-
PoolPrices,
|
|
8
|
-
AdapterExchangeParam,
|
|
9
|
-
SimpleExchangeParam,
|
|
10
|
-
PoolLiquidity,
|
|
11
|
-
Logger,
|
|
12
|
-
BigIntAsString,
|
|
13
|
-
OptimalSwapExchange,
|
|
14
|
-
ExchangeTxInfo,
|
|
15
|
-
PreprocessTransactionOptions,
|
|
16
|
-
NumberAsString,
|
|
17
|
-
DexExchangeParam,
|
|
18
|
-
} from '../../types';
|
|
19
|
-
import { SwapSide, Network, LIMIT_ORDER_PROVIDERS } from '../../constants';
|
|
20
|
-
import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
|
|
21
|
-
import { getBigIntPow, getDexKeysWithNetwork } from '../../utils';
|
|
22
|
-
import { IDex } from '../../dex/idex';
|
|
23
|
-
import { IDexHelper } from '../../dex-helper/idex-helper';
|
|
24
|
-
import {
|
|
25
|
-
ParaSwapLimitOrdersData,
|
|
26
|
-
ParaSwapOrderResponse,
|
|
27
|
-
ParaSwapOrderBookResponse,
|
|
28
|
-
OrderInfo,
|
|
29
|
-
ParaSwapOrderBook,
|
|
30
|
-
} from './types';
|
|
31
|
-
import { Adapters, ParaSwapLimitOrdersConfig } from './config';
|
|
32
|
-
import { LimitOrderExchange } from '../limit-order-exchange';
|
|
33
|
-
import { BI_MAX_UINT256 } from '../../bigint-constants';
|
|
34
|
-
import augustusRFQABI from '../../abi/paraswap-limit-orders/AugustusRFQ.abi.json';
|
|
35
|
-
import {
|
|
36
|
-
MAX_ORDERS_MULTI_FACTOR,
|
|
37
|
-
MAX_ORDERS_USED_FOR_SWAP,
|
|
38
|
-
ONE_ORDER_GASCOST,
|
|
39
|
-
} from './constant';
|
|
40
|
-
import BigNumber from 'bignumber.js';
|
|
41
|
-
|
|
42
|
-
const BLACKLIST_CACHE_PREFIX = `lo_blacklist`;
|
|
43
|
-
|
|
44
|
-
export class ParaSwapLimitOrders
|
|
45
|
-
extends LimitOrderExchange<ParaSwapOrderResponse, ParaSwapOrderBookResponse>
|
|
46
|
-
implements IDex<ParaSwapLimitOrdersData>
|
|
47
|
-
{
|
|
48
|
-
readonly hasConstantPriceLargeAmounts = false;
|
|
49
|
-
readonly needWrapNative = true;
|
|
50
|
-
readonly isFeeOnTransferSupported = false;
|
|
51
|
-
|
|
52
|
-
public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
|
|
53
|
-
getDexKeysWithNetwork(ParaSwapLimitOrdersConfig);
|
|
54
|
-
|
|
55
|
-
logger: Logger;
|
|
56
|
-
|
|
57
|
-
protected augustusRFQAddress: Address;
|
|
58
|
-
|
|
59
|
-
constructor(
|
|
60
|
-
protected network: Network,
|
|
61
|
-
dexKey: string,
|
|
62
|
-
protected dexHelper: IDexHelper,
|
|
63
|
-
protected adapters = Adapters[network] ? Adapters[network] : {},
|
|
64
|
-
protected rfqIface = new Interface(augustusRFQABI),
|
|
65
|
-
) {
|
|
66
|
-
super(dexHelper, dexKey);
|
|
67
|
-
this.augustusRFQAddress =
|
|
68
|
-
dexHelper.config.data.augustusRFQAddress.toLowerCase();
|
|
69
|
-
this.logger = dexHelper.getLogger(dexKey);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get limitOrderProviderName() {
|
|
73
|
-
return LIMIT_ORDER_PROVIDERS.PARASWAP;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
getAdapters(side: SwapSide): { name: string; index: number }[] | null {
|
|
77
|
-
return this.adapters[side] ? this.adapters[side] : null;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
getIdentifier(srcToken: Address, destToken: Address) {
|
|
81
|
-
// Expected lowered Addresses
|
|
82
|
-
return `${this.dexKey.toLowerCase()}_${srcToken}_${destToken}`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async isBlacklisted(userAddress: string): Promise<boolean> {
|
|
86
|
-
const value = await this.dexHelper.cache.rawget(
|
|
87
|
-
`${BLACKLIST_CACHE_PREFIX}_${userAddress}`.toLowerCase(),
|
|
88
|
-
);
|
|
89
|
-
if (value) {
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async getPoolIdentifiers(
|
|
97
|
-
srcToken: Token,
|
|
98
|
-
destToken: Token,
|
|
99
|
-
side: SwapSide,
|
|
100
|
-
blockNumber: number,
|
|
101
|
-
): Promise<string[]> {
|
|
102
|
-
const _srcToken = this.dexHelper.config.wrapETH(srcToken);
|
|
103
|
-
const _destToken = this.dexHelper.config.wrapETH(destToken);
|
|
104
|
-
|
|
105
|
-
const _srcAddress = _srcToken.address.toLowerCase();
|
|
106
|
-
const _destAddress = _destToken.address.toLowerCase();
|
|
107
|
-
|
|
108
|
-
if (_srcAddress === _destAddress) {
|
|
109
|
-
return [];
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const orderBook = await this._getLatestOrderBook(_srcAddress, _destAddress);
|
|
113
|
-
|
|
114
|
-
if (orderBook === null) return [];
|
|
115
|
-
|
|
116
|
-
return [this.getIdentifier(_srcAddress, _destAddress)];
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async getPricesVolume(
|
|
120
|
-
srcToken: Token,
|
|
121
|
-
destToken: Token,
|
|
122
|
-
amounts: bigint[],
|
|
123
|
-
side: SwapSide,
|
|
124
|
-
blockNumber: number,
|
|
125
|
-
limitPools?: string[],
|
|
126
|
-
): Promise<null | ExchangePrices<ParaSwapLimitOrdersData>> {
|
|
127
|
-
try {
|
|
128
|
-
const _srcToken = this.dexHelper.config.wrapETH(srcToken);
|
|
129
|
-
const _destToken = this.dexHelper.config.wrapETH(destToken);
|
|
130
|
-
|
|
131
|
-
const _srcAddress = _srcToken.address.toLowerCase();
|
|
132
|
-
const _destAddress = _destToken.address.toLowerCase();
|
|
133
|
-
|
|
134
|
-
if (_srcAddress === _destAddress) return null;
|
|
135
|
-
|
|
136
|
-
const expectedIdentifier = this.getIdentifier(_srcAddress, _destAddress);
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
limitPools !== undefined &&
|
|
140
|
-
!limitPools.some(p => p === expectedIdentifier)
|
|
141
|
-
)
|
|
142
|
-
return null;
|
|
143
|
-
|
|
144
|
-
const isSell = side === SwapSide.SELL;
|
|
145
|
-
const unitVolume = getBigIntPow(
|
|
146
|
-
isSell ? _srcToken.decimals : _destToken.decimals,
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
let orderBook = await this._getLatestOrderBook(_srcAddress, _destAddress);
|
|
150
|
-
|
|
151
|
-
if (orderBook === null) return null;
|
|
152
|
-
|
|
153
|
-
// Unit is volume is not increasing, so better to request separate
|
|
154
|
-
let {
|
|
155
|
-
prices: [unit],
|
|
156
|
-
} = this._getPrices([unitVolume], orderBook, isSell);
|
|
157
|
-
|
|
158
|
-
const { prices, gasCosts, maxOrdersCount } = this._getPrices(
|
|
159
|
-
amounts,
|
|
160
|
-
orderBook,
|
|
161
|
-
isSell,
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
if (unit === 0n) {
|
|
165
|
-
// If we didn't fulfill unit amount, scale up latest amount till unit
|
|
166
|
-
unit = (unitVolume * prices.slice(-1)[0]) / amounts.slice(-1)[0];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return [
|
|
170
|
-
{
|
|
171
|
-
unit,
|
|
172
|
-
prices,
|
|
173
|
-
data: {
|
|
174
|
-
orderInfos: null,
|
|
175
|
-
maxOrdersCount,
|
|
176
|
-
},
|
|
177
|
-
poolIdentifier: expectedIdentifier,
|
|
178
|
-
exchange: this.dexKey,
|
|
179
|
-
gasCost: gasCosts.map(v => Number(v)),
|
|
180
|
-
poolAddresses: [this.augustusRFQAddress],
|
|
181
|
-
},
|
|
182
|
-
];
|
|
183
|
-
} catch (e) {
|
|
184
|
-
this.logger.error(
|
|
185
|
-
`Error_getPricesVolume ${this.dexKey}: ${
|
|
186
|
-
srcToken.symbol || srcToken.address
|
|
187
|
-
}, ${destToken.symbol || destToken.address}, ${side}:`,
|
|
188
|
-
e,
|
|
189
|
-
);
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Returns estimated gas cost of calldata for this DEX in multiSwap
|
|
195
|
-
getCalldataGasCost(
|
|
196
|
-
poolPrices: PoolPrices<ParaSwapLimitOrdersData>,
|
|
197
|
-
): number | number[] {
|
|
198
|
-
const calculateCalldataGasCost = (g: number) => {
|
|
199
|
-
if (!g) return 0;
|
|
200
|
-
const numOrders = Number(BigInt(g) / ONE_ORDER_GASCOST);
|
|
201
|
-
return (
|
|
202
|
-
CALLDATA_GAS_COST.DEX_NO_PAYLOAD +
|
|
203
|
-
CALLDATA_GAS_COST.LENGTH_LARGE +
|
|
204
|
-
// Struct header
|
|
205
|
-
CALLDATA_GAS_COST.OFFSET_SMALL +
|
|
206
|
-
// Struct -> orderInfos[] header
|
|
207
|
-
CALLDATA_GAS_COST.OFFSET_SMALL +
|
|
208
|
-
// Struct -> orderInfos[]
|
|
209
|
-
CALLDATA_GAS_COST.LENGTH_SMALL +
|
|
210
|
-
// Struct -> orderInfos[0:numOrders] headers
|
|
211
|
-
CALLDATA_GAS_COST.OFFSET_SMALL +
|
|
212
|
-
CALLDATA_GAS_COST.OFFSET_LARGE * (numOrders - 1) +
|
|
213
|
-
// Struct -> orderInfos[0:numOrders]
|
|
214
|
-
numOrders *
|
|
215
|
-
// Struct -> orderInfos[i] -> order
|
|
216
|
-
(CALLDATA_GAS_COST.FULL_WORD +
|
|
217
|
-
CALLDATA_GAS_COST.TIMESTAMP +
|
|
218
|
-
CALLDATA_GAS_COST.ADDRESS +
|
|
219
|
-
CALLDATA_GAS_COST.ADDRESS +
|
|
220
|
-
CALLDATA_GAS_COST.ADDRESS +
|
|
221
|
-
CALLDATA_GAS_COST.ADDRESS +
|
|
222
|
-
CALLDATA_GAS_COST.AMOUNT +
|
|
223
|
-
CALLDATA_GAS_COST.AMOUNT +
|
|
224
|
-
// Struct -> orderInfos[i] -> signature header
|
|
225
|
-
CALLDATA_GAS_COST.OFFSET_LARGE +
|
|
226
|
-
// Struct -> orderInfos[i] -> takerTokenFillAmount
|
|
227
|
-
CALLDATA_GAS_COST.AMOUNT +
|
|
228
|
-
// Struct -> orderInfos[i] -> permitTakerAsset header
|
|
229
|
-
CALLDATA_GAS_COST.OFFSET_LARGE +
|
|
230
|
-
// Struct -> orderInfos[i] -> permitMakerAsset header
|
|
231
|
-
CALLDATA_GAS_COST.OFFSET_LARGE +
|
|
232
|
-
// Struct -> orderInfos[i] -> signature
|
|
233
|
-
CALLDATA_GAS_COST.LENGTH_SMALL +
|
|
234
|
-
CALLDATA_GAS_COST.FULL_WORD +
|
|
235
|
-
CALLDATA_GAS_COST.FULL_WORD +
|
|
236
|
-
CALLDATA_GAS_COST.wordNonZeroBytes(1) +
|
|
237
|
-
// Struct -> orderInfos[i] -> permitTakerAsset
|
|
238
|
-
CALLDATA_GAS_COST.ZERO +
|
|
239
|
-
// Struct -> orderInfos[i] -> permitMakerAsset
|
|
240
|
-
CALLDATA_GAS_COST.ZERO)
|
|
241
|
-
);
|
|
242
|
-
};
|
|
243
|
-
return typeof poolPrices.gasCost === 'number'
|
|
244
|
-
? calculateCalldataGasCost(poolPrices.gasCost)
|
|
245
|
-
: poolPrices.gasCost.map(calculateCalldataGasCost);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
async preProcessTransaction?(
|
|
249
|
-
optimalSwapExchange: OptimalSwapExchange<ParaSwapLimitOrdersData>,
|
|
250
|
-
srcToken: Token,
|
|
251
|
-
destToken: Token,
|
|
252
|
-
side: SwapSide,
|
|
253
|
-
options: PreprocessTransactionOptions,
|
|
254
|
-
): Promise<[OptimalSwapExchange<ParaSwapLimitOrdersData>, ExchangeTxInfo]> {
|
|
255
|
-
const userAddress = options.txOrigin;
|
|
256
|
-
|
|
257
|
-
const srcWrapped = this.dexHelper.config
|
|
258
|
-
.wrapETH(srcToken)
|
|
259
|
-
.address.toLowerCase();
|
|
260
|
-
const destWrapped = this.dexHelper.config
|
|
261
|
-
.wrapETH(destToken)
|
|
262
|
-
.address.toLowerCase();
|
|
263
|
-
|
|
264
|
-
const isSell = side === SwapSide.SELL;
|
|
265
|
-
const amountWithSlippage = isSell
|
|
266
|
-
? BigInt(
|
|
267
|
-
new BigNumber(optimalSwapExchange.destAmount.toString())
|
|
268
|
-
.times(options.slippageFactor)
|
|
269
|
-
.toFixed(0),
|
|
270
|
-
)
|
|
271
|
-
: BigInt(
|
|
272
|
-
options.slippageFactor
|
|
273
|
-
.times(optimalSwapExchange.srcAmount.toString())
|
|
274
|
-
.toFixed(0),
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
const { encodingValues, minDeadline } =
|
|
278
|
-
await this._prepareOrdersForTransaction(
|
|
279
|
-
srcWrapped,
|
|
280
|
-
destWrapped,
|
|
281
|
-
isSell ? optimalSwapExchange.srcAmount : amountWithSlippage.toString(),
|
|
282
|
-
isSell ? amountWithSlippage.toString() : optimalSwapExchange.destAmount,
|
|
283
|
-
side,
|
|
284
|
-
userAddress,
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
return [
|
|
288
|
-
{
|
|
289
|
-
...optimalSwapExchange,
|
|
290
|
-
data: { orderInfos: encodingValues },
|
|
291
|
-
},
|
|
292
|
-
{ deadline: minDeadline },
|
|
293
|
-
];
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
getTokenFromAddress?(address: Address): Token {
|
|
297
|
-
// We don't have predefined set of tokens with decimals
|
|
298
|
-
// Anyway we don't use decimals, so it is fine to do this
|
|
299
|
-
return { address, decimals: 0 };
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
getAdapterParam(
|
|
303
|
-
srcToken: string,
|
|
304
|
-
destToken: string,
|
|
305
|
-
srcAmount: string,
|
|
306
|
-
destAmount: string,
|
|
307
|
-
data: ParaSwapLimitOrdersData,
|
|
308
|
-
side: SwapSide,
|
|
309
|
-
): AdapterExchangeParam {
|
|
310
|
-
const { orderInfos } = data;
|
|
311
|
-
if (orderInfos === null) {
|
|
312
|
-
throw new Error(
|
|
313
|
-
`Error_${this.dexKey}_getAdapterParam payload is not received. It may be because of` +
|
|
314
|
-
`not calling preProcessTransaction before`,
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const isSell = side === SwapSide.SELL;
|
|
319
|
-
const orderInfoParamType = this.rfqIface.getFunction(
|
|
320
|
-
isSell ? 'tryBatchFillOrderTakerAmount' : 'tryBatchFillOrderMakerAmount',
|
|
321
|
-
).inputs[0];
|
|
322
|
-
|
|
323
|
-
const orderInfoTypes = orderInfoParamType.format(
|
|
324
|
-
ethers.utils.FormatTypes.full,
|
|
325
|
-
);
|
|
326
|
-
|
|
327
|
-
const payload = this.rfqIface._abiCoder.encode(
|
|
328
|
-
[`tuple(${orderInfoTypes})`],
|
|
329
|
-
[{ orderInfos }],
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
return {
|
|
333
|
-
targetExchange: this.augustusRFQAddress,
|
|
334
|
-
payload,
|
|
335
|
-
networkFee: '0',
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
async getSimpleParam(
|
|
340
|
-
srcToken: string,
|
|
341
|
-
destToken: string,
|
|
342
|
-
srcAmount: string,
|
|
343
|
-
destAmount: string,
|
|
344
|
-
data: ParaSwapLimitOrdersData,
|
|
345
|
-
side: SwapSide,
|
|
346
|
-
): Promise<SimpleExchangeParam> {
|
|
347
|
-
const { orderInfos } = data;
|
|
348
|
-
|
|
349
|
-
if (orderInfos === null) {
|
|
350
|
-
throw new Error(
|
|
351
|
-
`Error_${this.dexKey}_getAdapterParam payload is not received. It may be because of` +
|
|
352
|
-
`not calling preProcessTransaction before`,
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const isSell = side === SwapSide.SELL;
|
|
357
|
-
const swapData = this.rfqIface.encodeFunctionData(
|
|
358
|
-
isSell ? 'tryBatchFillOrderTakerAmount' : 'tryBatchFillOrderMakerAmount',
|
|
359
|
-
[orderInfos, isSell ? srcAmount : destAmount, this.augustusAddress],
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
return this.buildSimpleParamWithoutWETHConversion(
|
|
363
|
-
srcToken,
|
|
364
|
-
srcAmount,
|
|
365
|
-
destToken,
|
|
366
|
-
destAmount,
|
|
367
|
-
swapData,
|
|
368
|
-
this.augustusRFQAddress,
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
getDexParam(
|
|
373
|
-
srcToken: Address,
|
|
374
|
-
destToken: Address,
|
|
375
|
-
srcAmount: NumberAsString,
|
|
376
|
-
destAmount: NumberAsString,
|
|
377
|
-
recipient: Address,
|
|
378
|
-
data: ParaSwapLimitOrdersData,
|
|
379
|
-
side: SwapSide,
|
|
380
|
-
): DexExchangeParam {
|
|
381
|
-
const { orderInfos } = data;
|
|
382
|
-
|
|
383
|
-
if (orderInfos === null) {
|
|
384
|
-
throw new Error(
|
|
385
|
-
`Error_${this.dexKey}_getAdapterParam payload is not received. It may be because of` +
|
|
386
|
-
`not calling preProcessTransaction before`,
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const isSell = side === SwapSide.SELL;
|
|
391
|
-
const swapData = this.rfqIface.encodeFunctionData(
|
|
392
|
-
isSell ? 'tryBatchFillOrderTakerAmount' : 'tryBatchFillOrderMakerAmount',
|
|
393
|
-
[orderInfos, isSell ? srcAmount : destAmount, recipient],
|
|
394
|
-
);
|
|
395
|
-
|
|
396
|
-
return {
|
|
397
|
-
needWrapNative: this.needWrapNative,
|
|
398
|
-
dexFuncHasRecipient: true,
|
|
399
|
-
exchangeData: swapData,
|
|
400
|
-
targetExchange: this.augustusRFQAddress,
|
|
401
|
-
returnAmountPos: undefined,
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
async getTopPoolsForToken(
|
|
406
|
-
tokenAddress: Address,
|
|
407
|
-
limit: number,
|
|
408
|
-
): Promise<PoolLiquidity[]> {
|
|
409
|
-
return [];
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
private async _getLatestOrderBook(
|
|
413
|
-
src: Address,
|
|
414
|
-
dest: Address,
|
|
415
|
-
): Promise<ParaSwapOrderBook[] | null> {
|
|
416
|
-
const orderBookUnparsed = await this._limitOrderProvider!.fetchOrderBook(
|
|
417
|
-
this.network,
|
|
418
|
-
src,
|
|
419
|
-
dest,
|
|
420
|
-
);
|
|
421
|
-
|
|
422
|
-
if (orderBookUnparsed === null || orderBookUnparsed.length === 0) {
|
|
423
|
-
this.logger.trace(
|
|
424
|
-
`${this.dexKey}: No orderBook found for ${src} and ${dest} on ${this.network} network`,
|
|
425
|
-
);
|
|
426
|
-
return null;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
return orderBookUnparsed
|
|
430
|
-
.map(orderBook => ({
|
|
431
|
-
swappableMakerBalance: BigInt(orderBook.swappableMakerBalance),
|
|
432
|
-
swappableTakerBalance: BigInt(orderBook.swappableTakerBalance),
|
|
433
|
-
makerAmount: BigInt(orderBook.makerAmount),
|
|
434
|
-
takerAmount: BigInt(orderBook.takerAmount),
|
|
435
|
-
isFillOrKill: orderBook.isFillOrKill,
|
|
436
|
-
}))
|
|
437
|
-
.filter(
|
|
438
|
-
orderBook =>
|
|
439
|
-
orderBook.swappableMakerBalance > 0n &&
|
|
440
|
-
orderBook.swappableTakerBalance > 0n,
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
private async _prepareOrdersForTransaction(
|
|
445
|
-
srcToken: Address,
|
|
446
|
-
destToken: Address,
|
|
447
|
-
srcAmount: BigIntAsString,
|
|
448
|
-
destAmount: BigIntAsString,
|
|
449
|
-
side: SwapSide,
|
|
450
|
-
userAddress: Address,
|
|
451
|
-
): Promise<{
|
|
452
|
-
encodingValues: OrderInfo[];
|
|
453
|
-
minDeadline: bigint;
|
|
454
|
-
}> {
|
|
455
|
-
// I assume that srcToken and destToken are already wrapped
|
|
456
|
-
// And received orders are fully match the amount we need and the price
|
|
457
|
-
// without further checks and calculations
|
|
458
|
-
const orderInfos = await this._limitOrderProvider!.fetchAndReserveOrders(
|
|
459
|
-
this.network,
|
|
460
|
-
srcToken,
|
|
461
|
-
destToken,
|
|
462
|
-
srcAmount,
|
|
463
|
-
destAmount,
|
|
464
|
-
side,
|
|
465
|
-
userAddress,
|
|
466
|
-
);
|
|
467
|
-
|
|
468
|
-
if (orderInfos === null)
|
|
469
|
-
throw new Error(
|
|
470
|
-
`${
|
|
471
|
-
this.dexKey
|
|
472
|
-
}: No orders received from _limitOrderProvider fetchAndReserveOrders request with params: ${JSON.stringify(
|
|
473
|
-
{
|
|
474
|
-
network: this.network,
|
|
475
|
-
srcToken,
|
|
476
|
-
destToken,
|
|
477
|
-
srcAmount,
|
|
478
|
-
destAmount,
|
|
479
|
-
side,
|
|
480
|
-
userAddress,
|
|
481
|
-
},
|
|
482
|
-
)}`,
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
const encodingValues: OrderInfo[] = new Array(orderInfos.length);
|
|
486
|
-
|
|
487
|
-
let minDeadline = BI_MAX_UINT256;
|
|
488
|
-
for (const [i, orderInfo] of orderInfos.entries()) {
|
|
489
|
-
// Find minimum deadline value
|
|
490
|
-
const { order } = orderInfo;
|
|
491
|
-
|
|
492
|
-
const orderExpiryBigInt = BigInt(order.expiry);
|
|
493
|
-
minDeadline =
|
|
494
|
-
orderExpiryBigInt < minDeadline ? orderExpiryBigInt : minDeadline;
|
|
495
|
-
|
|
496
|
-
encodingValues[i] = {
|
|
497
|
-
order: {
|
|
498
|
-
nonceAndMeta: order.nonceAndMeta,
|
|
499
|
-
expiry: order.expiry,
|
|
500
|
-
makerAsset: order.makerAsset,
|
|
501
|
-
takerAsset: order.takerAsset,
|
|
502
|
-
maker: order.maker,
|
|
503
|
-
taker: order.taker,
|
|
504
|
-
makerAmount: order.makerAmount,
|
|
505
|
-
takerAmount: order.takerAmount,
|
|
506
|
-
},
|
|
507
|
-
signature: orderInfo.signature,
|
|
508
|
-
takerTokenFillAmount: orderInfo.takerTokenFillAmount,
|
|
509
|
-
permitTakerAsset: orderInfo.permitTakerAsset
|
|
510
|
-
? orderInfo.permitTakerAsset
|
|
511
|
-
: '0x',
|
|
512
|
-
permitMakerAsset: orderInfo.permitMakerAsset
|
|
513
|
-
? orderInfo.permitMakerAsset
|
|
514
|
-
: '0x',
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
return { encodingValues, minDeadline };
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
private _getPrices(
|
|
521
|
-
amounts: bigint[],
|
|
522
|
-
orderBook: ParaSwapOrderBook[],
|
|
523
|
-
isSell: boolean,
|
|
524
|
-
): { prices: bigint[]; gasCosts: bigint[]; maxOrdersCount: number } {
|
|
525
|
-
const prices = new Array<bigint>(amounts.length).fill(0n);
|
|
526
|
-
const gasCosts = new Array<bigint>(amounts.length).fill(0n);
|
|
527
|
-
let maxOrdersCount = 0;
|
|
528
|
-
|
|
529
|
-
const calcOutFunc = isSell
|
|
530
|
-
? this._calcMakerFromTakerAmount
|
|
531
|
-
: this._calcTakerFromMakerAmount;
|
|
532
|
-
|
|
533
|
-
const srcKeyAmount = isSell
|
|
534
|
-
? 'swappableTakerBalance'
|
|
535
|
-
: 'swappableMakerBalance';
|
|
536
|
-
const destKeyAmount = isSell
|
|
537
|
-
? 'swappableMakerBalance'
|
|
538
|
-
: 'swappableTakerBalance';
|
|
539
|
-
|
|
540
|
-
const orderThresholdDenominators = [
|
|
541
|
-
BigInt(MAX_ORDERS_USED_FOR_SWAP) * BigInt(MAX_ORDERS_MULTI_FACTOR),
|
|
542
|
-
BigInt(MAX_ORDERS_USED_FOR_SWAP),
|
|
543
|
-
];
|
|
544
|
-
|
|
545
|
-
for (const orderThresholdDenominator of orderThresholdDenominators) {
|
|
546
|
-
let latestFilteredOrderBook = orderBook;
|
|
547
|
-
for (const [i, amount] of amounts.entries()) {
|
|
548
|
-
if (!(prices[i] === 0n && gasCosts[i] === 0n)) {
|
|
549
|
-
// We don't want to recalculate prices if previous iterations succeeded
|
|
550
|
-
continue;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
if (amount === 0n) {
|
|
554
|
-
prices[i] = 0n;
|
|
555
|
-
gasCosts[i] = 0n;
|
|
556
|
-
continue;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
const amountThreshold = amount / orderThresholdDenominator;
|
|
560
|
-
|
|
561
|
-
latestFilteredOrderBook = latestFilteredOrderBook.filter(
|
|
562
|
-
ob => ob[srcKeyAmount] >= amountThreshold,
|
|
563
|
-
);
|
|
564
|
-
|
|
565
|
-
if (latestFilteredOrderBook.length === 0) {
|
|
566
|
-
prices[i] = 0n;
|
|
567
|
-
gasCosts[i] = 0n;
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
let toFill = amount;
|
|
572
|
-
let numberOfOrders = 0n;
|
|
573
|
-
let filled = 0n;
|
|
574
|
-
|
|
575
|
-
for (const order of latestFilteredOrderBook) {
|
|
576
|
-
if (toFill > 0n) {
|
|
577
|
-
if (toFill > order[srcKeyAmount]) {
|
|
578
|
-
toFill -= order[srcKeyAmount];
|
|
579
|
-
filled += order[destKeyAmount];
|
|
580
|
-
numberOfOrders++;
|
|
581
|
-
} else if (order.isFillOrKill) {
|
|
582
|
-
continue;
|
|
583
|
-
} else {
|
|
584
|
-
filled += calcOutFunc(
|
|
585
|
-
toFill,
|
|
586
|
-
order.makerAmount,
|
|
587
|
-
order.takerAmount,
|
|
588
|
-
);
|
|
589
|
-
toFill = 0n;
|
|
590
|
-
numberOfOrders++;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
if (numberOfOrders >= MAX_ORDERS_USED_FOR_SWAP) {
|
|
594
|
-
break;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if (numberOfOrders > MAX_ORDERS_USED_FOR_SWAP) {
|
|
599
|
-
prices[i] = 0n;
|
|
600
|
-
gasCosts[i] = 0n;
|
|
601
|
-
} else if (toFill === 0n) {
|
|
602
|
-
prices[i] = filled;
|
|
603
|
-
gasCosts[i] = numberOfOrders * ONE_ORDER_GASCOST;
|
|
604
|
-
maxOrdersCount = Math.max(maxOrdersCount, +numberOfOrders.toString());
|
|
605
|
-
} else {
|
|
606
|
-
prices[i] = 0n;
|
|
607
|
-
gasCosts[i] = 0n;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return { prices, gasCosts, maxOrdersCount };
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
private _calcTakerFromMakerAmount(
|
|
615
|
-
swappableMakerAmount: bigint,
|
|
616
|
-
makerAmount: bigint,
|
|
617
|
-
takerAmount: bigint,
|
|
618
|
-
): bigint {
|
|
619
|
-
return (
|
|
620
|
-
(swappableMakerAmount * takerAmount + (makerAmount - 1n)) / makerAmount
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
private _calcMakerFromTakerAmount(
|
|
625
|
-
swappableTakerAmount: bigint,
|
|
626
|
-
makerAmount: bigint,
|
|
627
|
-
takerAmount: bigint,
|
|
628
|
-
): bigint {
|
|
629
|
-
return (swappableTakerAmount * makerAmount) / takerAmount;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { Interface } from '@ethersproject/abi';
|
|
3
|
+
import {
|
|
4
|
+
Token,
|
|
5
|
+
Address,
|
|
6
|
+
ExchangePrices,
|
|
7
|
+
PoolPrices,
|
|
8
|
+
AdapterExchangeParam,
|
|
9
|
+
SimpleExchangeParam,
|
|
10
|
+
PoolLiquidity,
|
|
11
|
+
Logger,
|
|
12
|
+
BigIntAsString,
|
|
13
|
+
OptimalSwapExchange,
|
|
14
|
+
ExchangeTxInfo,
|
|
15
|
+
PreprocessTransactionOptions,
|
|
16
|
+
NumberAsString,
|
|
17
|
+
DexExchangeParam,
|
|
18
|
+
} from '../../types';
|
|
19
|
+
import { SwapSide, Network, LIMIT_ORDER_PROVIDERS } from '../../constants';
|
|
20
|
+
import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
|
|
21
|
+
import { getBigIntPow, getDexKeysWithNetwork } from '../../utils';
|
|
22
|
+
import { IDex } from '../../dex/idex';
|
|
23
|
+
import { IDexHelper } from '../../dex-helper/idex-helper';
|
|
24
|
+
import {
|
|
25
|
+
ParaSwapLimitOrdersData,
|
|
26
|
+
ParaSwapOrderResponse,
|
|
27
|
+
ParaSwapOrderBookResponse,
|
|
28
|
+
OrderInfo,
|
|
29
|
+
ParaSwapOrderBook,
|
|
30
|
+
} from './types';
|
|
31
|
+
import { Adapters, ParaSwapLimitOrdersConfig } from './config';
|
|
32
|
+
import { LimitOrderExchange } from '../limit-order-exchange';
|
|
33
|
+
import { BI_MAX_UINT256 } from '../../bigint-constants';
|
|
34
|
+
import augustusRFQABI from '../../abi/paraswap-limit-orders/AugustusRFQ.abi.json';
|
|
35
|
+
import {
|
|
36
|
+
MAX_ORDERS_MULTI_FACTOR,
|
|
37
|
+
MAX_ORDERS_USED_FOR_SWAP,
|
|
38
|
+
ONE_ORDER_GASCOST,
|
|
39
|
+
} from './constant';
|
|
40
|
+
import BigNumber from 'bignumber.js';
|
|
41
|
+
|
|
42
|
+
const BLACKLIST_CACHE_PREFIX = `lo_blacklist`;
|
|
43
|
+
|
|
44
|
+
export class ParaSwapLimitOrders
|
|
45
|
+
extends LimitOrderExchange<ParaSwapOrderResponse, ParaSwapOrderBookResponse>
|
|
46
|
+
implements IDex<ParaSwapLimitOrdersData>
|
|
47
|
+
{
|
|
48
|
+
readonly hasConstantPriceLargeAmounts = false;
|
|
49
|
+
readonly needWrapNative = true;
|
|
50
|
+
readonly isFeeOnTransferSupported = false;
|
|
51
|
+
|
|
52
|
+
public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
|
|
53
|
+
getDexKeysWithNetwork(ParaSwapLimitOrdersConfig);
|
|
54
|
+
|
|
55
|
+
logger: Logger;
|
|
56
|
+
|
|
57
|
+
protected augustusRFQAddress: Address;
|
|
58
|
+
|
|
59
|
+
constructor(
|
|
60
|
+
protected network: Network,
|
|
61
|
+
dexKey: string,
|
|
62
|
+
protected dexHelper: IDexHelper,
|
|
63
|
+
protected adapters = Adapters[network] ? Adapters[network] : {},
|
|
64
|
+
protected rfqIface = new Interface(augustusRFQABI),
|
|
65
|
+
) {
|
|
66
|
+
super(dexHelper, dexKey);
|
|
67
|
+
this.augustusRFQAddress =
|
|
68
|
+
dexHelper.config.data.augustusRFQAddress.toLowerCase();
|
|
69
|
+
this.logger = dexHelper.getLogger(dexKey);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get limitOrderProviderName() {
|
|
73
|
+
return LIMIT_ORDER_PROVIDERS.PARASWAP;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getAdapters(side: SwapSide): { name: string; index: number }[] | null {
|
|
77
|
+
return this.adapters[side] ? this.adapters[side] : null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
getIdentifier(srcToken: Address, destToken: Address) {
|
|
81
|
+
// Expected lowered Addresses
|
|
82
|
+
return `${this.dexKey.toLowerCase()}_${srcToken}_${destToken}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async isBlacklisted(userAddress: string): Promise<boolean> {
|
|
86
|
+
const value = await this.dexHelper.cache.rawget(
|
|
87
|
+
`${BLACKLIST_CACHE_PREFIX}_${userAddress}`.toLowerCase(),
|
|
88
|
+
);
|
|
89
|
+
if (value) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async getPoolIdentifiers(
|
|
97
|
+
srcToken: Token,
|
|
98
|
+
destToken: Token,
|
|
99
|
+
side: SwapSide,
|
|
100
|
+
blockNumber: number,
|
|
101
|
+
): Promise<string[]> {
|
|
102
|
+
const _srcToken = this.dexHelper.config.wrapETH(srcToken);
|
|
103
|
+
const _destToken = this.dexHelper.config.wrapETH(destToken);
|
|
104
|
+
|
|
105
|
+
const _srcAddress = _srcToken.address.toLowerCase();
|
|
106
|
+
const _destAddress = _destToken.address.toLowerCase();
|
|
107
|
+
|
|
108
|
+
if (_srcAddress === _destAddress) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const orderBook = await this._getLatestOrderBook(_srcAddress, _destAddress);
|
|
113
|
+
|
|
114
|
+
if (orderBook === null) return [];
|
|
115
|
+
|
|
116
|
+
return [this.getIdentifier(_srcAddress, _destAddress)];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getPricesVolume(
|
|
120
|
+
srcToken: Token,
|
|
121
|
+
destToken: Token,
|
|
122
|
+
amounts: bigint[],
|
|
123
|
+
side: SwapSide,
|
|
124
|
+
blockNumber: number,
|
|
125
|
+
limitPools?: string[],
|
|
126
|
+
): Promise<null | ExchangePrices<ParaSwapLimitOrdersData>> {
|
|
127
|
+
try {
|
|
128
|
+
const _srcToken = this.dexHelper.config.wrapETH(srcToken);
|
|
129
|
+
const _destToken = this.dexHelper.config.wrapETH(destToken);
|
|
130
|
+
|
|
131
|
+
const _srcAddress = _srcToken.address.toLowerCase();
|
|
132
|
+
const _destAddress = _destToken.address.toLowerCase();
|
|
133
|
+
|
|
134
|
+
if (_srcAddress === _destAddress) return null;
|
|
135
|
+
|
|
136
|
+
const expectedIdentifier = this.getIdentifier(_srcAddress, _destAddress);
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
limitPools !== undefined &&
|
|
140
|
+
!limitPools.some(p => p === expectedIdentifier)
|
|
141
|
+
)
|
|
142
|
+
return null;
|
|
143
|
+
|
|
144
|
+
const isSell = side === SwapSide.SELL;
|
|
145
|
+
const unitVolume = getBigIntPow(
|
|
146
|
+
isSell ? _srcToken.decimals : _destToken.decimals,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
let orderBook = await this._getLatestOrderBook(_srcAddress, _destAddress);
|
|
150
|
+
|
|
151
|
+
if (orderBook === null) return null;
|
|
152
|
+
|
|
153
|
+
// Unit is volume is not increasing, so better to request separate
|
|
154
|
+
let {
|
|
155
|
+
prices: [unit],
|
|
156
|
+
} = this._getPrices([unitVolume], orderBook, isSell);
|
|
157
|
+
|
|
158
|
+
const { prices, gasCosts, maxOrdersCount } = this._getPrices(
|
|
159
|
+
amounts,
|
|
160
|
+
orderBook,
|
|
161
|
+
isSell,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (unit === 0n) {
|
|
165
|
+
// If we didn't fulfill unit amount, scale up latest amount till unit
|
|
166
|
+
unit = (unitVolume * prices.slice(-1)[0]) / amounts.slice(-1)[0];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
unit,
|
|
172
|
+
prices,
|
|
173
|
+
data: {
|
|
174
|
+
orderInfos: null,
|
|
175
|
+
maxOrdersCount,
|
|
176
|
+
},
|
|
177
|
+
poolIdentifier: expectedIdentifier,
|
|
178
|
+
exchange: this.dexKey,
|
|
179
|
+
gasCost: gasCosts.map(v => Number(v)),
|
|
180
|
+
poolAddresses: [this.augustusRFQAddress],
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
} catch (e) {
|
|
184
|
+
this.logger.error(
|
|
185
|
+
`Error_getPricesVolume ${this.dexKey}: ${
|
|
186
|
+
srcToken.symbol || srcToken.address
|
|
187
|
+
}, ${destToken.symbol || destToken.address}, ${side}:`,
|
|
188
|
+
e,
|
|
189
|
+
);
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Returns estimated gas cost of calldata for this DEX in multiSwap
|
|
195
|
+
getCalldataGasCost(
|
|
196
|
+
poolPrices: PoolPrices<ParaSwapLimitOrdersData>,
|
|
197
|
+
): number | number[] {
|
|
198
|
+
const calculateCalldataGasCost = (g: number) => {
|
|
199
|
+
if (!g) return 0;
|
|
200
|
+
const numOrders = Number(BigInt(g) / ONE_ORDER_GASCOST);
|
|
201
|
+
return (
|
|
202
|
+
CALLDATA_GAS_COST.DEX_NO_PAYLOAD +
|
|
203
|
+
CALLDATA_GAS_COST.LENGTH_LARGE +
|
|
204
|
+
// Struct header
|
|
205
|
+
CALLDATA_GAS_COST.OFFSET_SMALL +
|
|
206
|
+
// Struct -> orderInfos[] header
|
|
207
|
+
CALLDATA_GAS_COST.OFFSET_SMALL +
|
|
208
|
+
// Struct -> orderInfos[]
|
|
209
|
+
CALLDATA_GAS_COST.LENGTH_SMALL +
|
|
210
|
+
// Struct -> orderInfos[0:numOrders] headers
|
|
211
|
+
CALLDATA_GAS_COST.OFFSET_SMALL +
|
|
212
|
+
CALLDATA_GAS_COST.OFFSET_LARGE * (numOrders - 1) +
|
|
213
|
+
// Struct -> orderInfos[0:numOrders]
|
|
214
|
+
numOrders *
|
|
215
|
+
// Struct -> orderInfos[i] -> order
|
|
216
|
+
(CALLDATA_GAS_COST.FULL_WORD +
|
|
217
|
+
CALLDATA_GAS_COST.TIMESTAMP +
|
|
218
|
+
CALLDATA_GAS_COST.ADDRESS +
|
|
219
|
+
CALLDATA_GAS_COST.ADDRESS +
|
|
220
|
+
CALLDATA_GAS_COST.ADDRESS +
|
|
221
|
+
CALLDATA_GAS_COST.ADDRESS +
|
|
222
|
+
CALLDATA_GAS_COST.AMOUNT +
|
|
223
|
+
CALLDATA_GAS_COST.AMOUNT +
|
|
224
|
+
// Struct -> orderInfos[i] -> signature header
|
|
225
|
+
CALLDATA_GAS_COST.OFFSET_LARGE +
|
|
226
|
+
// Struct -> orderInfos[i] -> takerTokenFillAmount
|
|
227
|
+
CALLDATA_GAS_COST.AMOUNT +
|
|
228
|
+
// Struct -> orderInfos[i] -> permitTakerAsset header
|
|
229
|
+
CALLDATA_GAS_COST.OFFSET_LARGE +
|
|
230
|
+
// Struct -> orderInfos[i] -> permitMakerAsset header
|
|
231
|
+
CALLDATA_GAS_COST.OFFSET_LARGE +
|
|
232
|
+
// Struct -> orderInfos[i] -> signature
|
|
233
|
+
CALLDATA_GAS_COST.LENGTH_SMALL +
|
|
234
|
+
CALLDATA_GAS_COST.FULL_WORD +
|
|
235
|
+
CALLDATA_GAS_COST.FULL_WORD +
|
|
236
|
+
CALLDATA_GAS_COST.wordNonZeroBytes(1) +
|
|
237
|
+
// Struct -> orderInfos[i] -> permitTakerAsset
|
|
238
|
+
CALLDATA_GAS_COST.ZERO +
|
|
239
|
+
// Struct -> orderInfos[i] -> permitMakerAsset
|
|
240
|
+
CALLDATA_GAS_COST.ZERO)
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
return typeof poolPrices.gasCost === 'number'
|
|
244
|
+
? calculateCalldataGasCost(poolPrices.gasCost)
|
|
245
|
+
: poolPrices.gasCost.map(calculateCalldataGasCost);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async preProcessTransaction?(
|
|
249
|
+
optimalSwapExchange: OptimalSwapExchange<ParaSwapLimitOrdersData>,
|
|
250
|
+
srcToken: Token,
|
|
251
|
+
destToken: Token,
|
|
252
|
+
side: SwapSide,
|
|
253
|
+
options: PreprocessTransactionOptions,
|
|
254
|
+
): Promise<[OptimalSwapExchange<ParaSwapLimitOrdersData>, ExchangeTxInfo]> {
|
|
255
|
+
const userAddress = options.txOrigin;
|
|
256
|
+
|
|
257
|
+
const srcWrapped = this.dexHelper.config
|
|
258
|
+
.wrapETH(srcToken)
|
|
259
|
+
.address.toLowerCase();
|
|
260
|
+
const destWrapped = this.dexHelper.config
|
|
261
|
+
.wrapETH(destToken)
|
|
262
|
+
.address.toLowerCase();
|
|
263
|
+
|
|
264
|
+
const isSell = side === SwapSide.SELL;
|
|
265
|
+
const amountWithSlippage = isSell
|
|
266
|
+
? BigInt(
|
|
267
|
+
new BigNumber(optimalSwapExchange.destAmount.toString())
|
|
268
|
+
.times(options.slippageFactor)
|
|
269
|
+
.toFixed(0),
|
|
270
|
+
)
|
|
271
|
+
: BigInt(
|
|
272
|
+
options.slippageFactor
|
|
273
|
+
.times(optimalSwapExchange.srcAmount.toString())
|
|
274
|
+
.toFixed(0),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const { encodingValues, minDeadline } =
|
|
278
|
+
await this._prepareOrdersForTransaction(
|
|
279
|
+
srcWrapped,
|
|
280
|
+
destWrapped,
|
|
281
|
+
isSell ? optimalSwapExchange.srcAmount : amountWithSlippage.toString(),
|
|
282
|
+
isSell ? amountWithSlippage.toString() : optimalSwapExchange.destAmount,
|
|
283
|
+
side,
|
|
284
|
+
userAddress,
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
return [
|
|
288
|
+
{
|
|
289
|
+
...optimalSwapExchange,
|
|
290
|
+
data: { orderInfos: encodingValues },
|
|
291
|
+
},
|
|
292
|
+
{ deadline: minDeadline },
|
|
293
|
+
];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
getTokenFromAddress?(address: Address): Token {
|
|
297
|
+
// We don't have predefined set of tokens with decimals
|
|
298
|
+
// Anyway we don't use decimals, so it is fine to do this
|
|
299
|
+
return { address, decimals: 0 };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
getAdapterParam(
|
|
303
|
+
srcToken: string,
|
|
304
|
+
destToken: string,
|
|
305
|
+
srcAmount: string,
|
|
306
|
+
destAmount: string,
|
|
307
|
+
data: ParaSwapLimitOrdersData,
|
|
308
|
+
side: SwapSide,
|
|
309
|
+
): AdapterExchangeParam {
|
|
310
|
+
const { orderInfos } = data;
|
|
311
|
+
if (orderInfos === null) {
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Error_${this.dexKey}_getAdapterParam payload is not received. It may be because of` +
|
|
314
|
+
`not calling preProcessTransaction before`,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const isSell = side === SwapSide.SELL;
|
|
319
|
+
const orderInfoParamType = this.rfqIface.getFunction(
|
|
320
|
+
isSell ? 'tryBatchFillOrderTakerAmount' : 'tryBatchFillOrderMakerAmount',
|
|
321
|
+
).inputs[0];
|
|
322
|
+
|
|
323
|
+
const orderInfoTypes = orderInfoParamType.format(
|
|
324
|
+
ethers.utils.FormatTypes.full,
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
const payload = this.rfqIface._abiCoder.encode(
|
|
328
|
+
[`tuple(${orderInfoTypes})`],
|
|
329
|
+
[{ orderInfos }],
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
targetExchange: this.augustusRFQAddress,
|
|
334
|
+
payload,
|
|
335
|
+
networkFee: '0',
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async getSimpleParam(
|
|
340
|
+
srcToken: string,
|
|
341
|
+
destToken: string,
|
|
342
|
+
srcAmount: string,
|
|
343
|
+
destAmount: string,
|
|
344
|
+
data: ParaSwapLimitOrdersData,
|
|
345
|
+
side: SwapSide,
|
|
346
|
+
): Promise<SimpleExchangeParam> {
|
|
347
|
+
const { orderInfos } = data;
|
|
348
|
+
|
|
349
|
+
if (orderInfos === null) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
`Error_${this.dexKey}_getAdapterParam payload is not received. It may be because of` +
|
|
352
|
+
`not calling preProcessTransaction before`,
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const isSell = side === SwapSide.SELL;
|
|
357
|
+
const swapData = this.rfqIface.encodeFunctionData(
|
|
358
|
+
isSell ? 'tryBatchFillOrderTakerAmount' : 'tryBatchFillOrderMakerAmount',
|
|
359
|
+
[orderInfos, isSell ? srcAmount : destAmount, this.augustusAddress],
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
return this.buildSimpleParamWithoutWETHConversion(
|
|
363
|
+
srcToken,
|
|
364
|
+
srcAmount,
|
|
365
|
+
destToken,
|
|
366
|
+
destAmount,
|
|
367
|
+
swapData,
|
|
368
|
+
this.augustusRFQAddress,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
getDexParam(
|
|
373
|
+
srcToken: Address,
|
|
374
|
+
destToken: Address,
|
|
375
|
+
srcAmount: NumberAsString,
|
|
376
|
+
destAmount: NumberAsString,
|
|
377
|
+
recipient: Address,
|
|
378
|
+
data: ParaSwapLimitOrdersData,
|
|
379
|
+
side: SwapSide,
|
|
380
|
+
): DexExchangeParam {
|
|
381
|
+
const { orderInfos } = data;
|
|
382
|
+
|
|
383
|
+
if (orderInfos === null) {
|
|
384
|
+
throw new Error(
|
|
385
|
+
`Error_${this.dexKey}_getAdapterParam payload is not received. It may be because of` +
|
|
386
|
+
`not calling preProcessTransaction before`,
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const isSell = side === SwapSide.SELL;
|
|
391
|
+
const swapData = this.rfqIface.encodeFunctionData(
|
|
392
|
+
isSell ? 'tryBatchFillOrderTakerAmount' : 'tryBatchFillOrderMakerAmount',
|
|
393
|
+
[orderInfos, isSell ? srcAmount : destAmount, recipient],
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
needWrapNative: this.needWrapNative,
|
|
398
|
+
dexFuncHasRecipient: true,
|
|
399
|
+
exchangeData: swapData,
|
|
400
|
+
targetExchange: this.augustusRFQAddress,
|
|
401
|
+
returnAmountPos: undefined,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async getTopPoolsForToken(
|
|
406
|
+
tokenAddress: Address,
|
|
407
|
+
limit: number,
|
|
408
|
+
): Promise<PoolLiquidity[]> {
|
|
409
|
+
return [];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private async _getLatestOrderBook(
|
|
413
|
+
src: Address,
|
|
414
|
+
dest: Address,
|
|
415
|
+
): Promise<ParaSwapOrderBook[] | null> {
|
|
416
|
+
const orderBookUnparsed = await this._limitOrderProvider!.fetchOrderBook(
|
|
417
|
+
this.network,
|
|
418
|
+
src,
|
|
419
|
+
dest,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
if (orderBookUnparsed === null || orderBookUnparsed.length === 0) {
|
|
423
|
+
this.logger.trace(
|
|
424
|
+
`${this.dexKey}: No orderBook found for ${src} and ${dest} on ${this.network} network`,
|
|
425
|
+
);
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return orderBookUnparsed
|
|
430
|
+
.map(orderBook => ({
|
|
431
|
+
swappableMakerBalance: BigInt(orderBook.swappableMakerBalance),
|
|
432
|
+
swappableTakerBalance: BigInt(orderBook.swappableTakerBalance),
|
|
433
|
+
makerAmount: BigInt(orderBook.makerAmount),
|
|
434
|
+
takerAmount: BigInt(orderBook.takerAmount),
|
|
435
|
+
isFillOrKill: orderBook.isFillOrKill,
|
|
436
|
+
}))
|
|
437
|
+
.filter(
|
|
438
|
+
orderBook =>
|
|
439
|
+
orderBook.swappableMakerBalance > 0n &&
|
|
440
|
+
orderBook.swappableTakerBalance > 0n,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private async _prepareOrdersForTransaction(
|
|
445
|
+
srcToken: Address,
|
|
446
|
+
destToken: Address,
|
|
447
|
+
srcAmount: BigIntAsString,
|
|
448
|
+
destAmount: BigIntAsString,
|
|
449
|
+
side: SwapSide,
|
|
450
|
+
userAddress: Address,
|
|
451
|
+
): Promise<{
|
|
452
|
+
encodingValues: OrderInfo[];
|
|
453
|
+
minDeadline: bigint;
|
|
454
|
+
}> {
|
|
455
|
+
// I assume that srcToken and destToken are already wrapped
|
|
456
|
+
// And received orders are fully match the amount we need and the price
|
|
457
|
+
// without further checks and calculations
|
|
458
|
+
const orderInfos = await this._limitOrderProvider!.fetchAndReserveOrders(
|
|
459
|
+
this.network,
|
|
460
|
+
srcToken,
|
|
461
|
+
destToken,
|
|
462
|
+
srcAmount,
|
|
463
|
+
destAmount,
|
|
464
|
+
side,
|
|
465
|
+
userAddress,
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
if (orderInfos === null)
|
|
469
|
+
throw new Error(
|
|
470
|
+
`${
|
|
471
|
+
this.dexKey
|
|
472
|
+
}: No orders received from _limitOrderProvider fetchAndReserveOrders request with params: ${JSON.stringify(
|
|
473
|
+
{
|
|
474
|
+
network: this.network,
|
|
475
|
+
srcToken,
|
|
476
|
+
destToken,
|
|
477
|
+
srcAmount,
|
|
478
|
+
destAmount,
|
|
479
|
+
side,
|
|
480
|
+
userAddress,
|
|
481
|
+
},
|
|
482
|
+
)}`,
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
const encodingValues: OrderInfo[] = new Array(orderInfos.length);
|
|
486
|
+
|
|
487
|
+
let minDeadline = BI_MAX_UINT256;
|
|
488
|
+
for (const [i, orderInfo] of orderInfos.entries()) {
|
|
489
|
+
// Find minimum deadline value
|
|
490
|
+
const { order } = orderInfo;
|
|
491
|
+
|
|
492
|
+
const orderExpiryBigInt = BigInt(order.expiry);
|
|
493
|
+
minDeadline =
|
|
494
|
+
orderExpiryBigInt < minDeadline ? orderExpiryBigInt : minDeadline;
|
|
495
|
+
|
|
496
|
+
encodingValues[i] = {
|
|
497
|
+
order: {
|
|
498
|
+
nonceAndMeta: order.nonceAndMeta,
|
|
499
|
+
expiry: order.expiry,
|
|
500
|
+
makerAsset: order.makerAsset,
|
|
501
|
+
takerAsset: order.takerAsset,
|
|
502
|
+
maker: order.maker,
|
|
503
|
+
taker: order.taker,
|
|
504
|
+
makerAmount: order.makerAmount,
|
|
505
|
+
takerAmount: order.takerAmount,
|
|
506
|
+
},
|
|
507
|
+
signature: orderInfo.signature,
|
|
508
|
+
takerTokenFillAmount: orderInfo.takerTokenFillAmount,
|
|
509
|
+
permitTakerAsset: orderInfo.permitTakerAsset
|
|
510
|
+
? orderInfo.permitTakerAsset
|
|
511
|
+
: '0x',
|
|
512
|
+
permitMakerAsset: orderInfo.permitMakerAsset
|
|
513
|
+
? orderInfo.permitMakerAsset
|
|
514
|
+
: '0x',
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
return { encodingValues, minDeadline };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
private _getPrices(
|
|
521
|
+
amounts: bigint[],
|
|
522
|
+
orderBook: ParaSwapOrderBook[],
|
|
523
|
+
isSell: boolean,
|
|
524
|
+
): { prices: bigint[]; gasCosts: bigint[]; maxOrdersCount: number } {
|
|
525
|
+
const prices = new Array<bigint>(amounts.length).fill(0n);
|
|
526
|
+
const gasCosts = new Array<bigint>(amounts.length).fill(0n);
|
|
527
|
+
let maxOrdersCount = 0;
|
|
528
|
+
|
|
529
|
+
const calcOutFunc = isSell
|
|
530
|
+
? this._calcMakerFromTakerAmount
|
|
531
|
+
: this._calcTakerFromMakerAmount;
|
|
532
|
+
|
|
533
|
+
const srcKeyAmount = isSell
|
|
534
|
+
? 'swappableTakerBalance'
|
|
535
|
+
: 'swappableMakerBalance';
|
|
536
|
+
const destKeyAmount = isSell
|
|
537
|
+
? 'swappableMakerBalance'
|
|
538
|
+
: 'swappableTakerBalance';
|
|
539
|
+
|
|
540
|
+
const orderThresholdDenominators = [
|
|
541
|
+
BigInt(MAX_ORDERS_USED_FOR_SWAP) * BigInt(MAX_ORDERS_MULTI_FACTOR),
|
|
542
|
+
BigInt(MAX_ORDERS_USED_FOR_SWAP),
|
|
543
|
+
];
|
|
544
|
+
|
|
545
|
+
for (const orderThresholdDenominator of orderThresholdDenominators) {
|
|
546
|
+
let latestFilteredOrderBook = orderBook;
|
|
547
|
+
for (const [i, amount] of amounts.entries()) {
|
|
548
|
+
if (!(prices[i] === 0n && gasCosts[i] === 0n)) {
|
|
549
|
+
// We don't want to recalculate prices if previous iterations succeeded
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (amount === 0n) {
|
|
554
|
+
prices[i] = 0n;
|
|
555
|
+
gasCosts[i] = 0n;
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const amountThreshold = amount / orderThresholdDenominator;
|
|
560
|
+
|
|
561
|
+
latestFilteredOrderBook = latestFilteredOrderBook.filter(
|
|
562
|
+
ob => ob[srcKeyAmount] >= amountThreshold,
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
if (latestFilteredOrderBook.length === 0) {
|
|
566
|
+
prices[i] = 0n;
|
|
567
|
+
gasCosts[i] = 0n;
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
let toFill = amount;
|
|
572
|
+
let numberOfOrders = 0n;
|
|
573
|
+
let filled = 0n;
|
|
574
|
+
|
|
575
|
+
for (const order of latestFilteredOrderBook) {
|
|
576
|
+
if (toFill > 0n) {
|
|
577
|
+
if (toFill > order[srcKeyAmount]) {
|
|
578
|
+
toFill -= order[srcKeyAmount];
|
|
579
|
+
filled += order[destKeyAmount];
|
|
580
|
+
numberOfOrders++;
|
|
581
|
+
} else if (order.isFillOrKill) {
|
|
582
|
+
continue;
|
|
583
|
+
} else {
|
|
584
|
+
filled += calcOutFunc(
|
|
585
|
+
toFill,
|
|
586
|
+
order.makerAmount,
|
|
587
|
+
order.takerAmount,
|
|
588
|
+
);
|
|
589
|
+
toFill = 0n;
|
|
590
|
+
numberOfOrders++;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (numberOfOrders >= MAX_ORDERS_USED_FOR_SWAP) {
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (numberOfOrders > MAX_ORDERS_USED_FOR_SWAP) {
|
|
599
|
+
prices[i] = 0n;
|
|
600
|
+
gasCosts[i] = 0n;
|
|
601
|
+
} else if (toFill === 0n) {
|
|
602
|
+
prices[i] = filled;
|
|
603
|
+
gasCosts[i] = numberOfOrders * ONE_ORDER_GASCOST;
|
|
604
|
+
maxOrdersCount = Math.max(maxOrdersCount, +numberOfOrders.toString());
|
|
605
|
+
} else {
|
|
606
|
+
prices[i] = 0n;
|
|
607
|
+
gasCosts[i] = 0n;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return { prices, gasCosts, maxOrdersCount };
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
private _calcTakerFromMakerAmount(
|
|
615
|
+
swappableMakerAmount: bigint,
|
|
616
|
+
makerAmount: bigint,
|
|
617
|
+
takerAmount: bigint,
|
|
618
|
+
): bigint {
|
|
619
|
+
return (
|
|
620
|
+
(swappableMakerAmount * takerAmount + (makerAmount - 1n)) / makerAmount
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private _calcMakerFromTakerAmount(
|
|
625
|
+
swappableTakerAmount: bigint,
|
|
626
|
+
makerAmount: bigint,
|
|
627
|
+
takerAmount: bigint,
|
|
628
|
+
): bigint {
|
|
629
|
+
return (swappableTakerAmount * makerAmount) / takerAmount;
|
|
630
|
+
}
|
|
631
|
+
}
|