novaswap-v2-sdk 1.0.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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/constants.d.ts +19 -0
- package/dist/entities/index.d.ts +3 -0
- package/dist/entities/pair.d.ts +147 -0
- package/dist/entities/route.d.ts +12 -0
- package/dist/entities/trade.d.ts +103 -0
- package/dist/errors.d.ts +16 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -0
- package/dist/novaswap-v2-sdk.cjs.development.js +1069 -0
- package/dist/novaswap-v2-sdk.cjs.development.js.map +1 -0
- package/dist/novaswap-v2-sdk.cjs.production.min.js +2 -0
- package/dist/novaswap-v2-sdk.cjs.production.min.js.map +1 -0
- package/dist/novaswap-v2-sdk.esm.js +1052 -0
- package/dist/novaswap-v2-sdk.esm.js.map +1 -0
- package/dist/router.d.ts +64 -0
- package/package.json +51 -0
|
@@ -0,0 +1,1052 @@
|
|
|
1
|
+
import { Percent, CurrencyAmount, sqrt, Token, Price, TradeType, Fraction, computePriceImpact, sortedInsert, validateAndParseAddress } from '@uniswap/sdk-core';
|
|
2
|
+
import { V2_FACTORY_ADDRESSES } from 'novaswap-core-sdk';
|
|
3
|
+
import JSBI from 'jsbi';
|
|
4
|
+
import { getCreate2Address } from '@ethersproject/address';
|
|
5
|
+
import { BigNumber } from '@ethersproject/bignumber';
|
|
6
|
+
import { keccak256, pack } from '@ethersproject/solidity';
|
|
7
|
+
import invariant from 'tiny-invariant';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated use FACTORY_ADDRESS_MAP instead
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
var FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f';
|
|
14
|
+
var FACTORY_ADDRESS_MAP = V2_FACTORY_ADDRESSES;
|
|
15
|
+
var INIT_CODE_HASH = '0x0ef7ca4700ff7e705236379af2cdac62d4fa0bbd010fb163697b63379941118e';
|
|
16
|
+
var MINIMUM_LIQUIDITY = /*#__PURE__*/JSBI.BigInt(1000); // exports for internal consumption
|
|
17
|
+
|
|
18
|
+
var ZERO = /*#__PURE__*/JSBI.BigInt(0);
|
|
19
|
+
var ONE = /*#__PURE__*/JSBI.BigInt(1);
|
|
20
|
+
var FIVE = /*#__PURE__*/JSBI.BigInt(5);
|
|
21
|
+
var _997 = /*#__PURE__*/JSBI.BigInt(997);
|
|
22
|
+
var _1000 = /*#__PURE__*/JSBI.BigInt(1000);
|
|
23
|
+
var BASIS_POINTS = /*#__PURE__*/JSBI.BigInt(10000);
|
|
24
|
+
var ZERO_PERCENT = /*#__PURE__*/new Percent(ZERO);
|
|
25
|
+
var ONE_HUNDRED_PERCENT = /*#__PURE__*/new Percent(ONE);
|
|
26
|
+
|
|
27
|
+
function _defineProperties(target, props) {
|
|
28
|
+
for (var i = 0; i < props.length; i++) {
|
|
29
|
+
var descriptor = props[i];
|
|
30
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
31
|
+
descriptor.configurable = true;
|
|
32
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
33
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function _createClass(Constructor, protoProps, staticProps) {
|
|
38
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
39
|
+
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
40
|
+
return Constructor;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function _inheritsLoose(subClass, superClass) {
|
|
44
|
+
subClass.prototype = Object.create(superClass.prototype);
|
|
45
|
+
subClass.prototype.constructor = subClass;
|
|
46
|
+
subClass.__proto__ = superClass;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function _getPrototypeOf(o) {
|
|
50
|
+
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
|
|
51
|
+
return o.__proto__ || Object.getPrototypeOf(o);
|
|
52
|
+
};
|
|
53
|
+
return _getPrototypeOf(o);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function _setPrototypeOf(o, p) {
|
|
57
|
+
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
|
|
58
|
+
o.__proto__ = p;
|
|
59
|
+
return o;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return _setPrototypeOf(o, p);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function _isNativeReflectConstruct() {
|
|
66
|
+
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
|
|
67
|
+
if (Reflect.construct.sham) return false;
|
|
68
|
+
if (typeof Proxy === "function") return true;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
|
|
72
|
+
return true;
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function _construct(Parent, args, Class) {
|
|
79
|
+
if (_isNativeReflectConstruct()) {
|
|
80
|
+
_construct = Reflect.construct;
|
|
81
|
+
} else {
|
|
82
|
+
_construct = function _construct(Parent, args, Class) {
|
|
83
|
+
var a = [null];
|
|
84
|
+
a.push.apply(a, args);
|
|
85
|
+
var Constructor = Function.bind.apply(Parent, a);
|
|
86
|
+
var instance = new Constructor();
|
|
87
|
+
if (Class) _setPrototypeOf(instance, Class.prototype);
|
|
88
|
+
return instance;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return _construct.apply(null, arguments);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function _isNativeFunction(fn) {
|
|
96
|
+
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function _wrapNativeSuper(Class) {
|
|
100
|
+
var _cache = typeof Map === "function" ? new Map() : undefined;
|
|
101
|
+
|
|
102
|
+
_wrapNativeSuper = function _wrapNativeSuper(Class) {
|
|
103
|
+
if (Class === null || !_isNativeFunction(Class)) return Class;
|
|
104
|
+
|
|
105
|
+
if (typeof Class !== "function") {
|
|
106
|
+
throw new TypeError("Super expression must either be null or a function");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (typeof _cache !== "undefined") {
|
|
110
|
+
if (_cache.has(Class)) return _cache.get(Class);
|
|
111
|
+
|
|
112
|
+
_cache.set(Class, Wrapper);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function Wrapper() {
|
|
116
|
+
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Wrapper.prototype = Object.create(Class.prototype, {
|
|
120
|
+
constructor: {
|
|
121
|
+
value: Wrapper,
|
|
122
|
+
enumerable: false,
|
|
123
|
+
writable: true,
|
|
124
|
+
configurable: true
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return _setPrototypeOf(Wrapper, Class);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return _wrapNativeSuper(Class);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function _assertThisInitialized(self) {
|
|
134
|
+
if (self === void 0) {
|
|
135
|
+
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return self;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function _unsupportedIterableToArray(o, minLen) {
|
|
142
|
+
if (!o) return;
|
|
143
|
+
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
144
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
145
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
146
|
+
if (n === "Map" || n === "Set") return Array.from(o);
|
|
147
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function _arrayLikeToArray(arr, len) {
|
|
151
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
152
|
+
|
|
153
|
+
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
154
|
+
|
|
155
|
+
return arr2;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
|
|
159
|
+
var it;
|
|
160
|
+
|
|
161
|
+
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
|
|
162
|
+
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
|
|
163
|
+
if (it) o = it;
|
|
164
|
+
var i = 0;
|
|
165
|
+
return function () {
|
|
166
|
+
if (i >= o.length) return {
|
|
167
|
+
done: true
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
done: false,
|
|
171
|
+
value: o[i++]
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
it = o[Symbol.iterator]();
|
|
180
|
+
return it.next.bind(it);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// see https://stackoverflow.com/a/41102306
|
|
184
|
+
var CAN_SET_PROTOTYPE = ('setPrototypeOf' in Object);
|
|
185
|
+
/**
|
|
186
|
+
* Indicates that the pair has insufficient reserves for a desired output amount. I.e. the amount of output cannot be
|
|
187
|
+
* obtained by sending any amount of input.
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
var InsufficientReservesError = /*#__PURE__*/function (_Error) {
|
|
191
|
+
_inheritsLoose(InsufficientReservesError, _Error);
|
|
192
|
+
|
|
193
|
+
function InsufficientReservesError() {
|
|
194
|
+
var _this;
|
|
195
|
+
|
|
196
|
+
_this = _Error.call(this) || this;
|
|
197
|
+
_this.isInsufficientReservesError = true;
|
|
198
|
+
_this.name = _this.constructor.name;
|
|
199
|
+
if (CAN_SET_PROTOTYPE) Object.setPrototypeOf(_assertThisInitialized(_this), (this instanceof InsufficientReservesError ? this.constructor : void 0).prototype);
|
|
200
|
+
return _this;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return InsufficientReservesError;
|
|
204
|
+
}( /*#__PURE__*/_wrapNativeSuper(Error));
|
|
205
|
+
/**
|
|
206
|
+
* Indicates that the input amount is too small to produce any amount of output. I.e. the amount of input sent is less
|
|
207
|
+
* than the price of a single unit of output after fees.
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
var InsufficientInputAmountError = /*#__PURE__*/function (_Error2) {
|
|
211
|
+
_inheritsLoose(InsufficientInputAmountError, _Error2);
|
|
212
|
+
|
|
213
|
+
function InsufficientInputAmountError() {
|
|
214
|
+
var _this2;
|
|
215
|
+
|
|
216
|
+
_this2 = _Error2.call(this) || this;
|
|
217
|
+
_this2.isInsufficientInputAmountError = true;
|
|
218
|
+
_this2.name = _this2.constructor.name;
|
|
219
|
+
if (CAN_SET_PROTOTYPE) Object.setPrototypeOf(_assertThisInitialized(_this2), (this instanceof InsufficientInputAmountError ? this.constructor : void 0).prototype);
|
|
220
|
+
return _this2;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return InsufficientInputAmountError;
|
|
224
|
+
}( /*#__PURE__*/_wrapNativeSuper(Error));
|
|
225
|
+
|
|
226
|
+
var computePairAddress = function computePairAddress(_ref) {
|
|
227
|
+
var factoryAddress = _ref.factoryAddress,
|
|
228
|
+
tokenA = _ref.tokenA,
|
|
229
|
+
tokenB = _ref.tokenB;
|
|
230
|
+
|
|
231
|
+
var _ref2 = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA],
|
|
232
|
+
token0 = _ref2[0],
|
|
233
|
+
token1 = _ref2[1]; // does safety checks
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
return getCreate2Address(factoryAddress, keccak256(['bytes'], [pack(['address', 'address'], [token0.address, token1.address])]), INIT_CODE_HASH);
|
|
237
|
+
};
|
|
238
|
+
var Pair = /*#__PURE__*/function () {
|
|
239
|
+
function Pair(currencyAmountA, tokenAmountB) {
|
|
240
|
+
var tokenAmounts = currencyAmountA.currency.sortsBefore(tokenAmountB.currency) // does safety checks
|
|
241
|
+
? [currencyAmountA, tokenAmountB] : [tokenAmountB, currencyAmountA];
|
|
242
|
+
this.liquidityToken = new Token(tokenAmounts[0].currency.chainId, Pair.getAddress(tokenAmounts[0].currency, tokenAmounts[1].currency), 18, 'UNI-V2', 'Uniswap V2');
|
|
243
|
+
this.tokenAmounts = tokenAmounts;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
Pair.getAddress = function getAddress(tokenA, tokenB) {
|
|
247
|
+
var _FACTORY_ADDRESS_MAP$;
|
|
248
|
+
|
|
249
|
+
var factoryAddress = (_FACTORY_ADDRESS_MAP$ = FACTORY_ADDRESS_MAP[tokenA.chainId]) != null ? _FACTORY_ADDRESS_MAP$ : FACTORY_ADDRESS;
|
|
250
|
+
return computePairAddress({
|
|
251
|
+
factoryAddress: factoryAddress,
|
|
252
|
+
tokenA: tokenA,
|
|
253
|
+
tokenB: tokenB
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Returns true if the token is either token0 or token1
|
|
258
|
+
* @param token to check
|
|
259
|
+
*/
|
|
260
|
+
;
|
|
261
|
+
|
|
262
|
+
var _proto = Pair.prototype;
|
|
263
|
+
|
|
264
|
+
_proto.involvesToken = function involvesToken(token) {
|
|
265
|
+
return token.equals(this.token0) || token.equals(this.token1);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Returns the current mid price of the pair in terms of token0, i.e. the ratio of reserve1 to reserve0
|
|
269
|
+
*/
|
|
270
|
+
;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Return the price of the given token in terms of the other token in the pair.
|
|
274
|
+
* @param token token to return price of
|
|
275
|
+
*/
|
|
276
|
+
_proto.priceOf = function priceOf(token) {
|
|
277
|
+
!this.involvesToken(token) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOKEN') : invariant(false) : void 0;
|
|
278
|
+
return token.equals(this.token0) ? this.token0Price : this.token1Price;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Returns the chain ID of the tokens in the pair.
|
|
282
|
+
*/
|
|
283
|
+
;
|
|
284
|
+
|
|
285
|
+
_proto.reserveOf = function reserveOf(token) {
|
|
286
|
+
!this.involvesToken(token) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOKEN') : invariant(false) : void 0;
|
|
287
|
+
return token.equals(this.token0) ? this.reserve0 : this.reserve1;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* getAmountOut is the linear algebra of reserve ratio against amountIn:amountOut.
|
|
291
|
+
* https://ethereum.stackexchange.com/questions/101629/what-is-math-for-uniswap-calculates-the-amountout-and-amountin-why-997-and-1000
|
|
292
|
+
* has the math deduction for the reserve calculation without fee-on-transfer fees.
|
|
293
|
+
*
|
|
294
|
+
* With fee-on-transfer tax, intuitively it's just:
|
|
295
|
+
* inputAmountWithFeeAndTax = 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn
|
|
296
|
+
* = (1 - amountIn.sellFeesBips / 10000) * amountInWithFee
|
|
297
|
+
* where amountInWithFee is the amountIn after taking out the LP fees
|
|
298
|
+
* outputAmountWithTax = amountOut * (1 - amountOut.buyFeesBips / 10000)
|
|
299
|
+
*
|
|
300
|
+
* But we are illustrating the math deduction below to ensure that's the case.
|
|
301
|
+
*
|
|
302
|
+
* before swap A * B = K where A = reserveIn B = reserveOut
|
|
303
|
+
*
|
|
304
|
+
* after swap A' * B' = K where only k is a constant value
|
|
305
|
+
*
|
|
306
|
+
* getAmountOut
|
|
307
|
+
*
|
|
308
|
+
* A' = A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn # here 0.3% is deducted
|
|
309
|
+
* B' = B - amountOut * (1 - amountOut.buyFeesBips / 10000)
|
|
310
|
+
* amountOut = (B - B') / (1 - amountOut.buyFeesBips / 10000) # where A' * B' still is k
|
|
311
|
+
* = (B - K/(A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn))
|
|
312
|
+
* /
|
|
313
|
+
* (1 - amountOut.buyFeesBips / 10000)
|
|
314
|
+
* = (B - AB/(A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn))
|
|
315
|
+
* /
|
|
316
|
+
* (1 - amountOut.buyFeesBips / 10000)
|
|
317
|
+
* = ((BA + B * 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn - AB)/(A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn))
|
|
318
|
+
* /
|
|
319
|
+
* (1 - amountOut.buyFeesBips / 10000)
|
|
320
|
+
* = (B * 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn / (A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn)
|
|
321
|
+
* /
|
|
322
|
+
* (1 - amountOut.buyFeesBips / 10000)
|
|
323
|
+
* amountOut * (1 - amountOut.buyFeesBips / 10000) = (B * 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn
|
|
324
|
+
* /
|
|
325
|
+
* (A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn)
|
|
326
|
+
*
|
|
327
|
+
* outputAmountWithTax = (B * 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn
|
|
328
|
+
* /
|
|
329
|
+
* (A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn)
|
|
330
|
+
* = (B * 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn * 1000
|
|
331
|
+
* /
|
|
332
|
+
* ((A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn) * 1000)
|
|
333
|
+
* = (B * (1 - amountIn.sellFeesBips / 10000) 997 * * amountIn
|
|
334
|
+
* /
|
|
335
|
+
* (1000 * A + (1 - amountIn.sellFeesBips / 10000) * 997 * amountIn)
|
|
336
|
+
* = (B * (1 - amountIn.sellFeesBips / 10000) * inputAmountWithFee)
|
|
337
|
+
* /
|
|
338
|
+
* (1000 * A + (1 - amountIn.sellFeesBips / 10000) * inputAmountWithFee)
|
|
339
|
+
* = (B * inputAmountWithFeeAndTax)
|
|
340
|
+
* /
|
|
341
|
+
* (1000 * A + inputAmountWithFeeAndTax)
|
|
342
|
+
*
|
|
343
|
+
* inputAmountWithFeeAndTax = (1 - amountIn.sellFeesBips / 10000) * inputAmountWithFee
|
|
344
|
+
* outputAmountWithTax = amountOut * (1 - amountOut.buyFeesBips / 10000)
|
|
345
|
+
*
|
|
346
|
+
* @param inputAmount
|
|
347
|
+
* @param calculateFotFees
|
|
348
|
+
*/
|
|
349
|
+
;
|
|
350
|
+
|
|
351
|
+
_proto.getOutputAmount = function getOutputAmount(inputAmount, calculateFotFees) {
|
|
352
|
+
if (calculateFotFees === void 0) {
|
|
353
|
+
calculateFotFees = true;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
!this.involvesToken(inputAmount.currency) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOKEN') : invariant(false) : void 0;
|
|
357
|
+
|
|
358
|
+
if (JSBI.equal(this.reserve0.quotient, ZERO) || JSBI.equal(this.reserve1.quotient, ZERO)) {
|
|
359
|
+
throw new InsufficientReservesError();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
var inputReserve = this.reserveOf(inputAmount.currency);
|
|
363
|
+
var outputReserve = this.reserveOf(inputAmount.currency.equals(this.token0) ? this.token1 : this.token0);
|
|
364
|
+
var percentAfterSellFees = calculateFotFees ? this.derivePercentAfterSellFees(inputAmount) : ZERO_PERCENT;
|
|
365
|
+
var inputAmountAfterTax = percentAfterSellFees.greaterThan(ZERO_PERCENT) ? CurrencyAmount.fromRawAmount(inputAmount.currency, percentAfterSellFees.multiply(inputAmount).quotient // fraction.quotient will round down by itself, which is desired
|
|
366
|
+
) : inputAmount;
|
|
367
|
+
var inputAmountWithFeeAndAfterTax = JSBI.multiply(inputAmountAfterTax.quotient, _997);
|
|
368
|
+
var numerator = JSBI.multiply(inputAmountWithFeeAndAfterTax, outputReserve.quotient);
|
|
369
|
+
var denominator = JSBI.add(JSBI.multiply(inputReserve.quotient, _1000), inputAmountWithFeeAndAfterTax);
|
|
370
|
+
var outputAmount = CurrencyAmount.fromRawAmount(inputAmount.currency.equals(this.token0) ? this.token1 : this.token0, JSBI.divide(numerator, denominator) // JSBI.divide will round down by itself, which is desired
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
if (JSBI.equal(outputAmount.quotient, ZERO)) {
|
|
374
|
+
throw new InsufficientInputAmountError();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
var percentAfterBuyFees = calculateFotFees ? this.derivePercentAfterBuyFees(outputAmount) : ZERO_PERCENT;
|
|
378
|
+
var outputAmountAfterTax = percentAfterBuyFees.greaterThan(ZERO_PERCENT) ? CurrencyAmount.fromRawAmount(outputAmount.currency, outputAmount.multiply(percentAfterBuyFees).quotient // fraction.quotient will round down by itself, which is desired
|
|
379
|
+
) : outputAmount;
|
|
380
|
+
|
|
381
|
+
if (JSBI.equal(outputAmountAfterTax.quotient, ZERO)) {
|
|
382
|
+
throw new InsufficientInputAmountError();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return [outputAmountAfterTax, new Pair(inputReserve.add(inputAmountAfterTax), outputReserve.subtract(outputAmountAfterTax))];
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* getAmountIn is the linear algebra of reserve ratio against amountIn:amountOut.
|
|
389
|
+
* https://ethereum.stackexchange.com/questions/101629/what-is-math-for-uniswap-calculates-the-amountout-and-amountin-why-997-and-1000
|
|
390
|
+
* has the math deduction for the reserve calculation without fee-on-transfer fees.
|
|
391
|
+
*
|
|
392
|
+
* With fee-on-transfer fees, intuitively it's just:
|
|
393
|
+
* outputAmountWithTax = amountOut / (1 - amountOut.buyFeesBips / 10000)
|
|
394
|
+
* inputAmountWithTax = amountIn / (1 - amountIn.sellFeesBips / 10000) / 0.997
|
|
395
|
+
*
|
|
396
|
+
* But we are illustrating the math deduction below to ensure that's the case.
|
|
397
|
+
*
|
|
398
|
+
* before swap A * B = K where A = reserveIn B = reserveOut
|
|
399
|
+
*
|
|
400
|
+
* after swap A' * B' = K where only k is a constant value
|
|
401
|
+
*
|
|
402
|
+
* getAmountIn
|
|
403
|
+
*
|
|
404
|
+
* B' = B - amountOut * (1 - amountOut.buyFeesBips / 10000)
|
|
405
|
+
* A' = A + 0.997 * (1 - amountIn.sellFeesBips / 10000) * amountIn # here 0.3% is deducted
|
|
406
|
+
* amountIn = (A' - A) / (0.997 * (1 - amountIn.sellFeesBips / 10000))
|
|
407
|
+
* = (K / (B - amountOut / (1 - amountOut.buyFeesBips / 10000)) - A)
|
|
408
|
+
* /
|
|
409
|
+
* (0.997 * (1 - amountIn.sellFeesBips / 10000))
|
|
410
|
+
* = (AB / (B - amountOut / (1 - amountOut.buyFeesBips / 10000)) - A)
|
|
411
|
+
* /
|
|
412
|
+
* (0.997 * (1 - amountIn.sellFeesBips / 10000))
|
|
413
|
+
* = ((AB - AB + A * amountOut / (1 - amountOut.buyFeesBips / 10000)) / (B - amountOut / (1 - amountOut.buyFeesBips / 10000)))
|
|
414
|
+
* /
|
|
415
|
+
* (0.997 * (1 - amountIn.sellFeesBips / 10000))
|
|
416
|
+
* = ((A * amountOut / (1 - amountOut.buyFeesBips / 10000)) / (B - amountOut / (1 - amountOut.buyFeesBips / 10000)))
|
|
417
|
+
* /
|
|
418
|
+
* (0.997 * (1 - amountIn.sellFeesBips / 10000))
|
|
419
|
+
* = ((A * 1000 * amountOut / (1 - amountOut.buyFeesBips / 10000)) / (B - amountOut / (1 - amountOut.buyFeesBips / 10000)))
|
|
420
|
+
* /
|
|
421
|
+
* (997 * (1 - amountIn.sellFeesBips / 10000))
|
|
422
|
+
*
|
|
423
|
+
* outputAmountWithTax = amountOut / (1 - amountOut.buyFeesBips / 10000)
|
|
424
|
+
* inputAmountWithTax = amountIn / (997 * (1 - amountIn.sellFeesBips / 10000))
|
|
425
|
+
* = (A * outputAmountWithTax * 1000) / ((B - outputAmountWithTax) * 997)
|
|
426
|
+
*
|
|
427
|
+
* @param outputAmount
|
|
428
|
+
*/
|
|
429
|
+
;
|
|
430
|
+
|
|
431
|
+
_proto.getInputAmount = function getInputAmount(outputAmount, calculateFotFees) {
|
|
432
|
+
if (calculateFotFees === void 0) {
|
|
433
|
+
calculateFotFees = true;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
!this.involvesToken(outputAmount.currency) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOKEN') : invariant(false) : void 0;
|
|
437
|
+
var percentAfterBuyFees = calculateFotFees ? this.derivePercentAfterBuyFees(outputAmount) : ZERO_PERCENT;
|
|
438
|
+
var outputAmountBeforeTax = percentAfterBuyFees.greaterThan(ZERO_PERCENT) ? CurrencyAmount.fromRawAmount(outputAmount.currency, JSBI.add(outputAmount.divide(percentAfterBuyFees).quotient, ONE) // add 1 for rounding up
|
|
439
|
+
) : outputAmount;
|
|
440
|
+
|
|
441
|
+
if (JSBI.equal(this.reserve0.quotient, ZERO) || JSBI.equal(this.reserve1.quotient, ZERO) || JSBI.greaterThanOrEqual(outputAmount.quotient, this.reserveOf(outputAmount.currency).quotient) || JSBI.greaterThanOrEqual(outputAmountBeforeTax.quotient, this.reserveOf(outputAmount.currency).quotient)) {
|
|
442
|
+
throw new InsufficientReservesError();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
var outputReserve = this.reserveOf(outputAmount.currency);
|
|
446
|
+
var inputReserve = this.reserveOf(outputAmount.currency.equals(this.token0) ? this.token1 : this.token0);
|
|
447
|
+
var numerator = JSBI.multiply(JSBI.multiply(inputReserve.quotient, outputAmountBeforeTax.quotient), _1000);
|
|
448
|
+
var denominator = JSBI.multiply(JSBI.subtract(outputReserve.quotient, outputAmountBeforeTax.quotient), _997);
|
|
449
|
+
var inputAmount = CurrencyAmount.fromRawAmount(outputAmount.currency.equals(this.token0) ? this.token1 : this.token0, JSBI.add(JSBI.divide(numerator, denominator), ONE) // add 1 here is part of the formula, no rounding needed here, since there will not be decimal at this point
|
|
450
|
+
);
|
|
451
|
+
var percentAfterSellFees = calculateFotFees ? this.derivePercentAfterSellFees(inputAmount) : ZERO_PERCENT;
|
|
452
|
+
var inputAmountBeforeTax = percentAfterSellFees.greaterThan(ZERO_PERCENT) ? CurrencyAmount.fromRawAmount(inputAmount.currency, JSBI.add(inputAmount.divide(percentAfterSellFees).quotient, ONE) // add 1 for rounding up
|
|
453
|
+
) : inputAmount;
|
|
454
|
+
return [inputAmountBeforeTax, new Pair(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))];
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
_proto.getLiquidityMinted = function getLiquidityMinted(totalSupply, tokenAmountA, tokenAmountB) {
|
|
458
|
+
!totalSupply.currency.equals(this.liquidityToken) ? process.env.NODE_ENV !== "production" ? invariant(false, 'LIQUIDITY') : invariant(false) : void 0;
|
|
459
|
+
var tokenAmounts = tokenAmountA.currency.sortsBefore(tokenAmountB.currency) // does safety checks
|
|
460
|
+
? [tokenAmountA, tokenAmountB] : [tokenAmountB, tokenAmountA];
|
|
461
|
+
!(tokenAmounts[0].currency.equals(this.token0) && tokenAmounts[1].currency.equals(this.token1)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOKEN') : invariant(false) : void 0;
|
|
462
|
+
var liquidity;
|
|
463
|
+
|
|
464
|
+
if (JSBI.equal(totalSupply.quotient, ZERO)) {
|
|
465
|
+
liquidity = JSBI.subtract(sqrt(JSBI.multiply(tokenAmounts[0].quotient, tokenAmounts[1].quotient)), MINIMUM_LIQUIDITY);
|
|
466
|
+
} else {
|
|
467
|
+
var amount0 = JSBI.divide(JSBI.multiply(tokenAmounts[0].quotient, totalSupply.quotient), this.reserve0.quotient);
|
|
468
|
+
var amount1 = JSBI.divide(JSBI.multiply(tokenAmounts[1].quotient, totalSupply.quotient), this.reserve1.quotient);
|
|
469
|
+
liquidity = JSBI.lessThanOrEqual(amount0, amount1) ? amount0 : amount1;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (!JSBI.greaterThan(liquidity, ZERO)) {
|
|
473
|
+
throw new InsufficientInputAmountError();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return CurrencyAmount.fromRawAmount(this.liquidityToken, liquidity);
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
_proto.getLiquidityValue = function getLiquidityValue(token, totalSupply, liquidity, feeOn, kLast) {
|
|
480
|
+
if (feeOn === void 0) {
|
|
481
|
+
feeOn = false;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
!this.involvesToken(token) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOKEN') : invariant(false) : void 0;
|
|
485
|
+
!totalSupply.currency.equals(this.liquidityToken) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TOTAL_SUPPLY') : invariant(false) : void 0;
|
|
486
|
+
!liquidity.currency.equals(this.liquidityToken) ? process.env.NODE_ENV !== "production" ? invariant(false, 'LIQUIDITY') : invariant(false) : void 0;
|
|
487
|
+
!JSBI.lessThanOrEqual(liquidity.quotient, totalSupply.quotient) ? process.env.NODE_ENV !== "production" ? invariant(false, 'LIQUIDITY') : invariant(false) : void 0;
|
|
488
|
+
var totalSupplyAdjusted;
|
|
489
|
+
|
|
490
|
+
if (!feeOn) {
|
|
491
|
+
totalSupplyAdjusted = totalSupply;
|
|
492
|
+
} else {
|
|
493
|
+
!!!kLast ? process.env.NODE_ENV !== "production" ? invariant(false, 'K_LAST') : invariant(false) : void 0;
|
|
494
|
+
var kLastParsed = JSBI.BigInt(kLast);
|
|
495
|
+
|
|
496
|
+
if (!JSBI.equal(kLastParsed, ZERO)) {
|
|
497
|
+
var rootK = sqrt(JSBI.multiply(this.reserve0.quotient, this.reserve1.quotient));
|
|
498
|
+
var rootKLast = sqrt(kLastParsed);
|
|
499
|
+
|
|
500
|
+
if (JSBI.greaterThan(rootK, rootKLast)) {
|
|
501
|
+
var numerator = JSBI.multiply(totalSupply.quotient, JSBI.subtract(rootK, rootKLast));
|
|
502
|
+
var denominator = JSBI.add(JSBI.multiply(rootK, FIVE), rootKLast);
|
|
503
|
+
var feeLiquidity = JSBI.divide(numerator, denominator);
|
|
504
|
+
totalSupplyAdjusted = totalSupply.add(CurrencyAmount.fromRawAmount(this.liquidityToken, feeLiquidity));
|
|
505
|
+
} else {
|
|
506
|
+
totalSupplyAdjusted = totalSupply;
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
totalSupplyAdjusted = totalSupply;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return CurrencyAmount.fromRawAmount(token, JSBI.divide(JSBI.multiply(liquidity.quotient, this.reserveOf(token).quotient), totalSupplyAdjusted.quotient));
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
_proto.derivePercentAfterSellFees = function derivePercentAfterSellFees(inputAmount) {
|
|
517
|
+
var sellFeeBips = this.token0.wrapped.equals(inputAmount.wrapped.currency) ? this.token0.wrapped.sellFeeBps : this.token1.wrapped.sellFeeBps;
|
|
518
|
+
|
|
519
|
+
if (sellFeeBips != null && sellFeeBips.gt(BigNumber.from(0))) {
|
|
520
|
+
return ONE_HUNDRED_PERCENT.subtract(new Percent(JSBI.BigInt(sellFeeBips)).divide(BASIS_POINTS));
|
|
521
|
+
} else {
|
|
522
|
+
return ZERO_PERCENT;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
_proto.derivePercentAfterBuyFees = function derivePercentAfterBuyFees(outputAmount) {
|
|
527
|
+
var buyFeeBps = this.token0.wrapped.equals(outputAmount.wrapped.currency) ? this.token0.wrapped.buyFeeBps : this.token1.wrapped.buyFeeBps;
|
|
528
|
+
|
|
529
|
+
if (buyFeeBps != null && buyFeeBps.gt(BigNumber.from(0))) {
|
|
530
|
+
return ONE_HUNDRED_PERCENT.subtract(new Percent(JSBI.BigInt(buyFeeBps)).divide(BASIS_POINTS));
|
|
531
|
+
} else {
|
|
532
|
+
return ZERO_PERCENT;
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
_createClass(Pair, [{
|
|
537
|
+
key: "token0Price",
|
|
538
|
+
get: function get() {
|
|
539
|
+
var result = this.tokenAmounts[1].divide(this.tokenAmounts[0]);
|
|
540
|
+
return new Price(this.token0, this.token1, result.denominator, result.numerator);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Returns the current mid price of the pair in terms of token1, i.e. the ratio of reserve0 to reserve1
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
}, {
|
|
547
|
+
key: "token1Price",
|
|
548
|
+
get: function get() {
|
|
549
|
+
var result = this.tokenAmounts[0].divide(this.tokenAmounts[1]);
|
|
550
|
+
return new Price(this.token1, this.token0, result.denominator, result.numerator);
|
|
551
|
+
}
|
|
552
|
+
}, {
|
|
553
|
+
key: "chainId",
|
|
554
|
+
get: function get() {
|
|
555
|
+
return this.token0.chainId;
|
|
556
|
+
}
|
|
557
|
+
}, {
|
|
558
|
+
key: "token0",
|
|
559
|
+
get: function get() {
|
|
560
|
+
return this.tokenAmounts[0].currency;
|
|
561
|
+
}
|
|
562
|
+
}, {
|
|
563
|
+
key: "token1",
|
|
564
|
+
get: function get() {
|
|
565
|
+
return this.tokenAmounts[1].currency;
|
|
566
|
+
}
|
|
567
|
+
}, {
|
|
568
|
+
key: "reserve0",
|
|
569
|
+
get: function get() {
|
|
570
|
+
return this.tokenAmounts[0];
|
|
571
|
+
}
|
|
572
|
+
}, {
|
|
573
|
+
key: "reserve1",
|
|
574
|
+
get: function get() {
|
|
575
|
+
return this.tokenAmounts[1];
|
|
576
|
+
}
|
|
577
|
+
}]);
|
|
578
|
+
|
|
579
|
+
return Pair;
|
|
580
|
+
}();
|
|
581
|
+
|
|
582
|
+
var Route = /*#__PURE__*/function () {
|
|
583
|
+
function Route(pairs, input, output) {
|
|
584
|
+
this._midPrice = null;
|
|
585
|
+
!(pairs.length > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'PAIRS') : invariant(false) : void 0;
|
|
586
|
+
var chainId = pairs[0].chainId;
|
|
587
|
+
!pairs.every(function (pair) {
|
|
588
|
+
return pair.chainId === chainId;
|
|
589
|
+
}) ? process.env.NODE_ENV !== "production" ? invariant(false, 'CHAIN_IDS') : invariant(false) : void 0;
|
|
590
|
+
var wrappedInput = input.wrapped;
|
|
591
|
+
!pairs[0].involvesToken(wrappedInput) ? process.env.NODE_ENV !== "production" ? invariant(false, 'INPUT') : invariant(false) : void 0;
|
|
592
|
+
!(typeof output === 'undefined' || pairs[pairs.length - 1].involvesToken(output.wrapped)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'OUTPUT') : invariant(false) : void 0;
|
|
593
|
+
var path = [wrappedInput];
|
|
594
|
+
|
|
595
|
+
for (var _iterator = _createForOfIteratorHelperLoose(pairs.entries()), _step; !(_step = _iterator()).done;) {
|
|
596
|
+
var _step$value = _step.value,
|
|
597
|
+
i = _step$value[0],
|
|
598
|
+
pair = _step$value[1];
|
|
599
|
+
var currentInput = path[i];
|
|
600
|
+
!(currentInput.equals(pair.token0) || currentInput.equals(pair.token1)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'PATH') : invariant(false) : void 0;
|
|
601
|
+
|
|
602
|
+
var _output = currentInput.equals(pair.token0) ? pair.token1 : pair.token0;
|
|
603
|
+
|
|
604
|
+
path.push(_output);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
this.pairs = pairs;
|
|
608
|
+
this.path = path;
|
|
609
|
+
this.input = input;
|
|
610
|
+
this.output = output;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
_createClass(Route, [{
|
|
614
|
+
key: "midPrice",
|
|
615
|
+
get: function get() {
|
|
616
|
+
if (this._midPrice !== null) return this._midPrice;
|
|
617
|
+
var prices = [];
|
|
618
|
+
|
|
619
|
+
for (var _iterator2 = _createForOfIteratorHelperLoose(this.pairs.entries()), _step2; !(_step2 = _iterator2()).done;) {
|
|
620
|
+
var _step2$value = _step2.value,
|
|
621
|
+
i = _step2$value[0],
|
|
622
|
+
pair = _step2$value[1];
|
|
623
|
+
prices.push(this.path[i].equals(pair.token0) ? new Price(pair.reserve0.currency, pair.reserve1.currency, pair.reserve0.quotient, pair.reserve1.quotient) : new Price(pair.reserve1.currency, pair.reserve0.currency, pair.reserve1.quotient, pair.reserve0.quotient));
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
var reduced = prices.slice(1).reduce(function (accumulator, currentValue) {
|
|
627
|
+
return accumulator.multiply(currentValue);
|
|
628
|
+
}, prices[0]);
|
|
629
|
+
return this._midPrice = new Price(this.input, this.output, reduced.denominator, reduced.numerator);
|
|
630
|
+
}
|
|
631
|
+
}, {
|
|
632
|
+
key: "chainId",
|
|
633
|
+
get: function get() {
|
|
634
|
+
return this.pairs[0].chainId;
|
|
635
|
+
}
|
|
636
|
+
}]);
|
|
637
|
+
|
|
638
|
+
return Route;
|
|
639
|
+
}();
|
|
640
|
+
|
|
641
|
+
// in increasing order. i.e. the best trades have the most outputs for the least inputs and are sorted first
|
|
642
|
+
|
|
643
|
+
function inputOutputComparator(a, b) {
|
|
644
|
+
// must have same input and output token for comparison
|
|
645
|
+
!a.inputAmount.currency.equals(b.inputAmount.currency) ? process.env.NODE_ENV !== "production" ? invariant(false, 'INPUT_CURRENCY') : invariant(false) : void 0;
|
|
646
|
+
!a.outputAmount.currency.equals(b.outputAmount.currency) ? process.env.NODE_ENV !== "production" ? invariant(false, 'OUTPUT_CURRENCY') : invariant(false) : void 0;
|
|
647
|
+
|
|
648
|
+
if (a.outputAmount.equalTo(b.outputAmount)) {
|
|
649
|
+
if (a.inputAmount.equalTo(b.inputAmount)) {
|
|
650
|
+
return 0;
|
|
651
|
+
} // trade A requires less input than trade B, so A should come first
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
if (a.inputAmount.lessThan(b.inputAmount)) {
|
|
655
|
+
return -1;
|
|
656
|
+
} else {
|
|
657
|
+
return 1;
|
|
658
|
+
}
|
|
659
|
+
} else {
|
|
660
|
+
// tradeA has less output than trade B, so should come second
|
|
661
|
+
if (a.outputAmount.lessThan(b.outputAmount)) {
|
|
662
|
+
return 1;
|
|
663
|
+
} else {
|
|
664
|
+
return -1;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
} // extension of the input output comparator that also considers other dimensions of the trade in ranking them
|
|
668
|
+
|
|
669
|
+
function tradeComparator(a, b) {
|
|
670
|
+
var ioComp = inputOutputComparator(a, b);
|
|
671
|
+
|
|
672
|
+
if (ioComp !== 0) {
|
|
673
|
+
return ioComp;
|
|
674
|
+
} // consider lowest slippage next, since these are less likely to fail
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
if (a.priceImpact.lessThan(b.priceImpact)) {
|
|
678
|
+
return -1;
|
|
679
|
+
} else if (a.priceImpact.greaterThan(b.priceImpact)) {
|
|
680
|
+
return 1;
|
|
681
|
+
} // finally consider the number of hops since each hop costs gas
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
return a.route.path.length - b.route.path.length;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Represents a trade executed against a list of pairs.
|
|
688
|
+
* Does not account for slippage, i.e. trades that front run this trade and move the price.
|
|
689
|
+
*/
|
|
690
|
+
|
|
691
|
+
var Trade = /*#__PURE__*/function () {
|
|
692
|
+
function Trade(route, amount, tradeType) {
|
|
693
|
+
this.route = route;
|
|
694
|
+
this.tradeType = tradeType;
|
|
695
|
+
var tokenAmounts = new Array(route.path.length);
|
|
696
|
+
|
|
697
|
+
if (tradeType === TradeType.EXACT_INPUT) {
|
|
698
|
+
!amount.currency.equals(route.input) ? process.env.NODE_ENV !== "production" ? invariant(false, 'INPUT') : invariant(false) : void 0;
|
|
699
|
+
tokenAmounts[0] = amount.wrapped;
|
|
700
|
+
|
|
701
|
+
for (var i = 0; i < route.path.length - 1; i++) {
|
|
702
|
+
var pair = route.pairs[i];
|
|
703
|
+
|
|
704
|
+
var _pair$getOutputAmount = pair.getOutputAmount(tokenAmounts[i]),
|
|
705
|
+
outputAmount = _pair$getOutputAmount[0];
|
|
706
|
+
|
|
707
|
+
tokenAmounts[i + 1] = outputAmount;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
this.inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
|
|
711
|
+
this.outputAmount = CurrencyAmount.fromFractionalAmount(route.output, tokenAmounts[tokenAmounts.length - 1].numerator, tokenAmounts[tokenAmounts.length - 1].denominator);
|
|
712
|
+
} else {
|
|
713
|
+
!amount.currency.equals(route.output) ? process.env.NODE_ENV !== "production" ? invariant(false, 'OUTPUT') : invariant(false) : void 0;
|
|
714
|
+
tokenAmounts[tokenAmounts.length - 1] = amount.wrapped;
|
|
715
|
+
|
|
716
|
+
for (var _i = route.path.length - 1; _i > 0; _i--) {
|
|
717
|
+
var _pair = route.pairs[_i - 1];
|
|
718
|
+
|
|
719
|
+
var _pair$getInputAmount = _pair.getInputAmount(tokenAmounts[_i]),
|
|
720
|
+
inputAmount = _pair$getInputAmount[0];
|
|
721
|
+
|
|
722
|
+
tokenAmounts[_i - 1] = inputAmount;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
this.inputAmount = CurrencyAmount.fromFractionalAmount(route.input, tokenAmounts[0].numerator, tokenAmounts[0].denominator);
|
|
726
|
+
this.outputAmount = CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
this.executionPrice = new Price(this.inputAmount.currency, this.outputAmount.currency, this.inputAmount.quotient, this.outputAmount.quotient);
|
|
730
|
+
this.priceImpact = computePriceImpact(route.midPrice, this.inputAmount, this.outputAmount);
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Constructs an exact in trade with the given amount in and route
|
|
734
|
+
* @param route route of the exact in trade
|
|
735
|
+
* @param amountIn the amount being passed in
|
|
736
|
+
*/
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
Trade.exactIn = function exactIn(route, amountIn) {
|
|
740
|
+
return new Trade(route, amountIn, TradeType.EXACT_INPUT);
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Constructs an exact out trade with the given amount out and route
|
|
744
|
+
* @param route route of the exact out trade
|
|
745
|
+
* @param amountOut the amount returned by the trade
|
|
746
|
+
*/
|
|
747
|
+
;
|
|
748
|
+
|
|
749
|
+
Trade.exactOut = function exactOut(route, amountOut) {
|
|
750
|
+
return new Trade(route, amountOut, TradeType.EXACT_OUTPUT);
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Get the minimum amount that must be received from this trade for the given slippage tolerance
|
|
754
|
+
* @param slippageTolerance tolerance of unfavorable slippage from the execution price of this trade
|
|
755
|
+
*/
|
|
756
|
+
;
|
|
757
|
+
|
|
758
|
+
var _proto = Trade.prototype;
|
|
759
|
+
|
|
760
|
+
_proto.minimumAmountOut = function minimumAmountOut(slippageTolerance) {
|
|
761
|
+
!!slippageTolerance.lessThan(ZERO) ? process.env.NODE_ENV !== "production" ? invariant(false, 'SLIPPAGE_TOLERANCE') : invariant(false) : void 0;
|
|
762
|
+
|
|
763
|
+
if (this.tradeType === TradeType.EXACT_OUTPUT) {
|
|
764
|
+
return this.outputAmount;
|
|
765
|
+
} else {
|
|
766
|
+
var slippageAdjustedAmountOut = new Fraction(ONE).add(slippageTolerance).invert().multiply(this.outputAmount.quotient).quotient;
|
|
767
|
+
return CurrencyAmount.fromRawAmount(this.outputAmount.currency, slippageAdjustedAmountOut);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Get the maximum amount in that can be spent via this trade for the given slippage tolerance
|
|
772
|
+
* @param slippageTolerance tolerance of unfavorable slippage from the execution price of this trade
|
|
773
|
+
*/
|
|
774
|
+
;
|
|
775
|
+
|
|
776
|
+
_proto.maximumAmountIn = function maximumAmountIn(slippageTolerance) {
|
|
777
|
+
!!slippageTolerance.lessThan(ZERO) ? process.env.NODE_ENV !== "production" ? invariant(false, 'SLIPPAGE_TOLERANCE') : invariant(false) : void 0;
|
|
778
|
+
|
|
779
|
+
if (this.tradeType === TradeType.EXACT_INPUT) {
|
|
780
|
+
return this.inputAmount;
|
|
781
|
+
} else {
|
|
782
|
+
var slippageAdjustedAmountIn = new Fraction(ONE).add(slippageTolerance).multiply(this.inputAmount.quotient).quotient;
|
|
783
|
+
return CurrencyAmount.fromRawAmount(this.inputAmount.currency, slippageAdjustedAmountIn);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Given a list of pairs, and a fixed amount in, returns the top `maxNumResults` trades that go from an input token
|
|
788
|
+
* amount to an output token, making at most `maxHops` hops.
|
|
789
|
+
* Note this does not consider aggregation, as routes are linear. It's possible a better route exists by splitting
|
|
790
|
+
* the amount in among multiple routes.
|
|
791
|
+
* @param pairs the pairs to consider in finding the best trade
|
|
792
|
+
* @param nextAmountIn exact amount of input currency to spend
|
|
793
|
+
* @param currencyOut the desired currency out
|
|
794
|
+
* @param maxNumResults maximum number of results to return
|
|
795
|
+
* @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pair
|
|
796
|
+
* @param currentPairs used in recursion; the current list of pairs
|
|
797
|
+
* @param currencyAmountIn used in recursion; the original value of the currencyAmountIn parameter
|
|
798
|
+
* @param bestTrades used in recursion; the current list of best trades
|
|
799
|
+
*/
|
|
800
|
+
;
|
|
801
|
+
|
|
802
|
+
Trade.bestTradeExactIn = function bestTradeExactIn(pairs, currencyAmountIn, currencyOut, _temp, // used in recursion.
|
|
803
|
+
currentPairs, nextAmountIn, bestTrades) {
|
|
804
|
+
var _ref = _temp === void 0 ? {} : _temp,
|
|
805
|
+
_ref$maxNumResults = _ref.maxNumResults,
|
|
806
|
+
maxNumResults = _ref$maxNumResults === void 0 ? 3 : _ref$maxNumResults,
|
|
807
|
+
_ref$maxHops = _ref.maxHops,
|
|
808
|
+
maxHops = _ref$maxHops === void 0 ? 3 : _ref$maxHops;
|
|
809
|
+
|
|
810
|
+
if (currentPairs === void 0) {
|
|
811
|
+
currentPairs = [];
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if (nextAmountIn === void 0) {
|
|
815
|
+
nextAmountIn = currencyAmountIn;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (bestTrades === void 0) {
|
|
819
|
+
bestTrades = [];
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
!(pairs.length > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'PAIRS') : invariant(false) : void 0;
|
|
823
|
+
!(maxHops > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MAX_HOPS') : invariant(false) : void 0;
|
|
824
|
+
!(currencyAmountIn === nextAmountIn || currentPairs.length > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'INVALID_RECURSION') : invariant(false) : void 0;
|
|
825
|
+
var amountIn = nextAmountIn.wrapped;
|
|
826
|
+
var tokenOut = currencyOut.wrapped;
|
|
827
|
+
|
|
828
|
+
for (var i = 0; i < pairs.length; i++) {
|
|
829
|
+
var pair = pairs[i]; // pair irrelevant
|
|
830
|
+
|
|
831
|
+
if (!pair.token0.equals(amountIn.currency) && !pair.token1.equals(amountIn.currency)) continue;
|
|
832
|
+
if (pair.reserve0.equalTo(ZERO) || pair.reserve1.equalTo(ZERO)) continue;
|
|
833
|
+
var amountOut = void 0;
|
|
834
|
+
|
|
835
|
+
try {
|
|
836
|
+
;
|
|
837
|
+
|
|
838
|
+
var _pair$getOutputAmount2 = pair.getOutputAmount(amountIn);
|
|
839
|
+
|
|
840
|
+
amountOut = _pair$getOutputAmount2[0];
|
|
841
|
+
} catch (error) {
|
|
842
|
+
// input too low
|
|
843
|
+
if (error.isInsufficientInputAmountError) {
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
throw error;
|
|
848
|
+
} // we have arrived at the output token, so this is the final trade of one of the paths
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
if (amountOut.currency.equals(tokenOut)) {
|
|
852
|
+
sortedInsert(bestTrades, new Trade(new Route([].concat(currentPairs, [pair]), currencyAmountIn.currency, currencyOut), currencyAmountIn, TradeType.EXACT_INPUT), maxNumResults, tradeComparator);
|
|
853
|
+
} else if (maxHops > 1 && pairs.length > 1) {
|
|
854
|
+
var pairsExcludingThisPair = pairs.slice(0, i).concat(pairs.slice(i + 1, pairs.length)); // otherwise, consider all the other paths that lead from this token as long as we have not exceeded maxHops
|
|
855
|
+
|
|
856
|
+
Trade.bestTradeExactIn(pairsExcludingThisPair, currencyAmountIn, currencyOut, {
|
|
857
|
+
maxNumResults: maxNumResults,
|
|
858
|
+
maxHops: maxHops - 1
|
|
859
|
+
}, [].concat(currentPairs, [pair]), amountOut, bestTrades);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
return bestTrades;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Return the execution price after accounting for slippage tolerance
|
|
867
|
+
* @param slippageTolerance the allowed tolerated slippage
|
|
868
|
+
*/
|
|
869
|
+
;
|
|
870
|
+
|
|
871
|
+
_proto.worstExecutionPrice = function worstExecutionPrice(slippageTolerance) {
|
|
872
|
+
return new Price(this.inputAmount.currency, this.outputAmount.currency, this.maximumAmountIn(slippageTolerance).quotient, this.minimumAmountOut(slippageTolerance).quotient);
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* similar to the above method but instead targets a fixed output amount
|
|
876
|
+
* given a list of pairs, and a fixed amount out, returns the top `maxNumResults` trades that go from an input token
|
|
877
|
+
* to an output token amount, making at most `maxHops` hops
|
|
878
|
+
* note this does not consider aggregation, as routes are linear. it's possible a better route exists by splitting
|
|
879
|
+
* the amount in among multiple routes.
|
|
880
|
+
* @param pairs the pairs to consider in finding the best trade
|
|
881
|
+
* @param currencyIn the currency to spend
|
|
882
|
+
* @param nextAmountOut the exact amount of currency out
|
|
883
|
+
* @param maxNumResults maximum number of results to return
|
|
884
|
+
* @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pair
|
|
885
|
+
* @param currentPairs used in recursion; the current list of pairs
|
|
886
|
+
* @param currencyAmountOut used in recursion; the original value of the currencyAmountOut parameter
|
|
887
|
+
* @param bestTrades used in recursion; the current list of best trades
|
|
888
|
+
*/
|
|
889
|
+
;
|
|
890
|
+
|
|
891
|
+
Trade.bestTradeExactOut = function bestTradeExactOut(pairs, currencyIn, currencyAmountOut, _temp2, // used in recursion.
|
|
892
|
+
currentPairs, nextAmountOut, bestTrades) {
|
|
893
|
+
var _ref2 = _temp2 === void 0 ? {} : _temp2,
|
|
894
|
+
_ref2$maxNumResults = _ref2.maxNumResults,
|
|
895
|
+
maxNumResults = _ref2$maxNumResults === void 0 ? 3 : _ref2$maxNumResults,
|
|
896
|
+
_ref2$maxHops = _ref2.maxHops,
|
|
897
|
+
maxHops = _ref2$maxHops === void 0 ? 3 : _ref2$maxHops;
|
|
898
|
+
|
|
899
|
+
if (currentPairs === void 0) {
|
|
900
|
+
currentPairs = [];
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (nextAmountOut === void 0) {
|
|
904
|
+
nextAmountOut = currencyAmountOut;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
if (bestTrades === void 0) {
|
|
908
|
+
bestTrades = [];
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
!(pairs.length > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'PAIRS') : invariant(false) : void 0;
|
|
912
|
+
!(maxHops > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MAX_HOPS') : invariant(false) : void 0;
|
|
913
|
+
!(currencyAmountOut === nextAmountOut || currentPairs.length > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'INVALID_RECURSION') : invariant(false) : void 0;
|
|
914
|
+
var amountOut = nextAmountOut.wrapped;
|
|
915
|
+
var tokenIn = currencyIn.wrapped;
|
|
916
|
+
|
|
917
|
+
for (var i = 0; i < pairs.length; i++) {
|
|
918
|
+
var pair = pairs[i]; // pair irrelevant
|
|
919
|
+
|
|
920
|
+
if (!pair.token0.equals(amountOut.currency) && !pair.token1.equals(amountOut.currency)) continue;
|
|
921
|
+
if (pair.reserve0.equalTo(ZERO) || pair.reserve1.equalTo(ZERO)) continue;
|
|
922
|
+
var amountIn = void 0;
|
|
923
|
+
|
|
924
|
+
try {
|
|
925
|
+
;
|
|
926
|
+
|
|
927
|
+
var _pair$getInputAmount2 = pair.getInputAmount(amountOut);
|
|
928
|
+
|
|
929
|
+
amountIn = _pair$getInputAmount2[0];
|
|
930
|
+
} catch (error) {
|
|
931
|
+
// not enough liquidity in this pair
|
|
932
|
+
if (error.isInsufficientReservesError) {
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
throw error;
|
|
937
|
+
} // we have arrived at the input token, so this is the first trade of one of the paths
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
if (amountIn.currency.equals(tokenIn)) {
|
|
941
|
+
sortedInsert(bestTrades, new Trade(new Route([pair].concat(currentPairs), currencyIn, currencyAmountOut.currency), currencyAmountOut, TradeType.EXACT_OUTPUT), maxNumResults, tradeComparator);
|
|
942
|
+
} else if (maxHops > 1 && pairs.length > 1) {
|
|
943
|
+
var pairsExcludingThisPair = pairs.slice(0, i).concat(pairs.slice(i + 1, pairs.length)); // otherwise, consider all the other paths that arrive at this token as long as we have not exceeded maxHops
|
|
944
|
+
|
|
945
|
+
Trade.bestTradeExactOut(pairsExcludingThisPair, currencyIn, currencyAmountOut, {
|
|
946
|
+
maxNumResults: maxNumResults,
|
|
947
|
+
maxHops: maxHops - 1
|
|
948
|
+
}, [pair].concat(currentPairs), amountIn, bestTrades);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
return bestTrades;
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
return Trade;
|
|
956
|
+
}();
|
|
957
|
+
|
|
958
|
+
function toHex(currencyAmount) {
|
|
959
|
+
return "0x" + currencyAmount.quotient.toString(16);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
var ZERO_HEX = '0x0';
|
|
963
|
+
/**
|
|
964
|
+
* Represents the Uniswap V2 Router, and has static methods for helping execute trades.
|
|
965
|
+
*/
|
|
966
|
+
|
|
967
|
+
var Router = /*#__PURE__*/function () {
|
|
968
|
+
/**
|
|
969
|
+
* Cannot be constructed.
|
|
970
|
+
*/
|
|
971
|
+
function Router() {}
|
|
972
|
+
/**
|
|
973
|
+
* Produces the on-chain method name to call and the hex encoded parameters to pass as arguments for a given trade.
|
|
974
|
+
* @param trade to produce call parameters for
|
|
975
|
+
* @param options options for the call parameters
|
|
976
|
+
*/
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
Router.swapCallParameters = function swapCallParameters(trade, options) {
|
|
980
|
+
var etherIn = trade.inputAmount.currency.isNative;
|
|
981
|
+
var etherOut = trade.outputAmount.currency.isNative; // the router does not support both ether in and out
|
|
982
|
+
|
|
983
|
+
!!(etherIn && etherOut) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ETHER_IN_OUT') : invariant(false) : void 0;
|
|
984
|
+
!(!('ttl' in options) || options.ttl > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'TTL') : invariant(false) : void 0;
|
|
985
|
+
var to = validateAndParseAddress(options.recipient);
|
|
986
|
+
var amountIn = toHex(trade.maximumAmountIn(options.allowedSlippage));
|
|
987
|
+
var amountOut = toHex(trade.minimumAmountOut(options.allowedSlippage));
|
|
988
|
+
var path = trade.route.path.map(function (token) {
|
|
989
|
+
return token.address;
|
|
990
|
+
});
|
|
991
|
+
var deadline = 'ttl' in options ? "0x" + (Math.floor(new Date().getTime() / 1000) + options.ttl).toString(16) : "0x" + options.deadline.toString(16);
|
|
992
|
+
var useFeeOnTransfer = Boolean(options.feeOnTransfer);
|
|
993
|
+
var methodName;
|
|
994
|
+
var args;
|
|
995
|
+
var value;
|
|
996
|
+
|
|
997
|
+
switch (trade.tradeType) {
|
|
998
|
+
case TradeType.EXACT_INPUT:
|
|
999
|
+
if (etherIn) {
|
|
1000
|
+
methodName = useFeeOnTransfer ? 'swapExactETHForTokensSupportingFeeOnTransferTokens' : 'swapExactETHForTokens'; // (uint amountOutMin, address[] calldata path, address to, uint deadline)
|
|
1001
|
+
|
|
1002
|
+
args = [amountOut, path, to, deadline];
|
|
1003
|
+
value = amountIn;
|
|
1004
|
+
} else if (etherOut) {
|
|
1005
|
+
methodName = useFeeOnTransfer ? 'swapExactTokensForETHSupportingFeeOnTransferTokens' : 'swapExactTokensForETH'; // (uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
|
|
1006
|
+
|
|
1007
|
+
args = [amountIn, amountOut, path, to, deadline];
|
|
1008
|
+
value = ZERO_HEX;
|
|
1009
|
+
} else {
|
|
1010
|
+
methodName = useFeeOnTransfer ? 'swapExactTokensForTokensSupportingFeeOnTransferTokens' : 'swapExactTokensForTokens'; // (uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
|
|
1011
|
+
|
|
1012
|
+
args = [amountIn, amountOut, path, to, deadline];
|
|
1013
|
+
value = ZERO_HEX;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
break;
|
|
1017
|
+
|
|
1018
|
+
case TradeType.EXACT_OUTPUT:
|
|
1019
|
+
!!useFeeOnTransfer ? process.env.NODE_ENV !== "production" ? invariant(false, 'EXACT_OUT_FOT') : invariant(false) : void 0;
|
|
1020
|
+
|
|
1021
|
+
if (etherIn) {
|
|
1022
|
+
methodName = 'swapETHForExactTokens'; // (uint amountOut, address[] calldata path, address to, uint deadline)
|
|
1023
|
+
|
|
1024
|
+
args = [amountOut, path, to, deadline];
|
|
1025
|
+
value = amountIn;
|
|
1026
|
+
} else if (etherOut) {
|
|
1027
|
+
methodName = 'swapTokensForExactETH'; // (uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
|
|
1028
|
+
|
|
1029
|
+
args = [amountOut, amountIn, path, to, deadline];
|
|
1030
|
+
value = ZERO_HEX;
|
|
1031
|
+
} else {
|
|
1032
|
+
methodName = 'swapTokensForExactTokens'; // (uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
|
|
1033
|
+
|
|
1034
|
+
args = [amountOut, amountIn, path, to, deadline];
|
|
1035
|
+
value = ZERO_HEX;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
break;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
return {
|
|
1042
|
+
methodName: methodName,
|
|
1043
|
+
args: args,
|
|
1044
|
+
value: value
|
|
1045
|
+
};
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
return Router;
|
|
1049
|
+
}();
|
|
1050
|
+
|
|
1051
|
+
export { FACTORY_ADDRESS_MAP, INIT_CODE_HASH, InsufficientInputAmountError, InsufficientReservesError, MINIMUM_LIQUIDITY, Pair, Route, Router, Trade, computePairAddress, inputOutputComparator, tradeComparator };
|
|
1052
|
+
//# sourceMappingURL=novaswap-v2-sdk.esm.js.map
|