impermax-sdk 1.1.59 → 1.1.61
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/lib/abis/contracts/ICollateral.json +20 -0
- package/lib/onchain/account/lendingPool/onchainAccountLendingPool.d.ts +2 -5
- package/lib/onchain/account/lendingPool/onchainAccountLendingPool.js +51 -33
- package/lib/onchain/impermaxFactory/lendingPool/onchainLendingPool.d.ts +2 -0
- package/lib/onchain/impermaxFactory/lendingPool/onchainLendingPool.js +91 -5
- package/lib/onchain/interactions/lendingPool/onchainInteractionsLendingPool.js +1 -0
- package/lib/utils/lliquidity-math.d.ts +25 -0
- package/lib/utils/lliquidity-math.js +124 -0
- package/lib/utils/price-from-reserves.js +2 -3
- package/package.json +1 -1
|
@@ -713,6 +713,26 @@
|
|
|
713
713
|
"stateMutability": "nonpayable",
|
|
714
714
|
"type": "function"
|
|
715
715
|
},
|
|
716
|
+
{
|
|
717
|
+
"constant": false,
|
|
718
|
+
"inputs": [],
|
|
719
|
+
"name": "geReserves",
|
|
720
|
+
"outputs": [
|
|
721
|
+
{
|
|
722
|
+
"internalType": "uint112",
|
|
723
|
+
"name": "reserve0",
|
|
724
|
+
"type": "uint112"
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
"internalType": "uint112",
|
|
728
|
+
"name": "reserve1",
|
|
729
|
+
"type": "uint112"
|
|
730
|
+
}
|
|
731
|
+
],
|
|
732
|
+
"payable": false,
|
|
733
|
+
"stateMutability": "nonpayable",
|
|
734
|
+
"type": "function"
|
|
735
|
+
},
|
|
716
736
|
{
|
|
717
737
|
"constant": false,
|
|
718
738
|
"inputs": [],
|
|
@@ -2,7 +2,7 @@ import OnchainAccount from '../index';
|
|
|
2
2
|
import { PoolTokenType } from '../../../config/types';
|
|
3
3
|
import OnchainAccountCollateral from './onchainAccountCollateral';
|
|
4
4
|
import OnchainAccountBorrowable from './onchainAccountBorrowable';
|
|
5
|
-
import { Changes, PendingRewardUI
|
|
5
|
+
import { Changes, PendingRewardUI } from '../../onchainTypes';
|
|
6
6
|
import OnchainLendingPool from '../../impermaxFactory/lendingPool';
|
|
7
7
|
import OnchainAccountPoolToken from '../onchainAccountPoolToken';
|
|
8
8
|
import OnchainInteractionsLendingPool from '../../interactions/lendingPool';
|
|
@@ -50,10 +50,7 @@ export default class OnchainAccountLendingPool {
|
|
|
50
50
|
valueB: number;
|
|
51
51
|
}>;
|
|
52
52
|
getLeverage(changes?: Changes): Promise<number>;
|
|
53
|
-
|
|
54
|
-
getLiquidationPricesGivenValues(values: Values): Promise<[number, number]>;
|
|
55
|
-
getLiquidationPriceSwings(changes?: Changes): Promise<[number, number]>;
|
|
56
|
-
getLiquidationPrices(changes?: Changes): Promise<[number, number]>;
|
|
53
|
+
getLiquidationPrices(changes?: Changes): Promise<number[]>;
|
|
57
54
|
getMaxLeverage(): Promise<number>;
|
|
58
55
|
getMaxDeleverage(slippage: number): Promise<number>;
|
|
59
56
|
getAvailableReward(): Promise<PendingRewardUI[]>;
|
|
@@ -16,6 +16,8 @@ const types_1 = require("../../../config/types");
|
|
|
16
16
|
const onchainAccountCollateral_1 = __importDefault(require("./onchainAccountCollateral"));
|
|
17
17
|
const onchainAccountBorrowable_1 = __importDefault(require("./onchainAccountBorrowable"));
|
|
18
18
|
const onchainTypes_1 = require("../../onchainTypes");
|
|
19
|
+
const factories_1 = require("../../../config/factories");
|
|
20
|
+
const lliquidity_math_1 = require("../../../utils/lliquidity-math");
|
|
19
21
|
class OnchainAccountLendingPool {
|
|
20
22
|
constructor(account, lendingPool) {
|
|
21
23
|
this.cache = {};
|
|
@@ -155,46 +157,62 @@ class OnchainAccountLendingPool {
|
|
|
155
157
|
});
|
|
156
158
|
}
|
|
157
159
|
// Liquidation Threshold
|
|
158
|
-
getLiquidationPriceSwingsGivenValues(values) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const t = (actualCollateral + rad) / (2 * Math.sqrt(safetyMargin));
|
|
172
|
-
let priceSwingA = Math.pow((t / valueA), 2);
|
|
173
|
-
let priceSwingB = Math.pow((t / valueB), 2);
|
|
174
|
-
return [priceSwingA, priceSwingB];
|
|
175
|
-
});
|
|
160
|
+
/*public async getLiquidationPriceSwingsGivenValues(values: Values) : Promise<[number, number]> {
|
|
161
|
+
if (!values) return [Infinity, Infinity];
|
|
162
|
+
const { valueCollateral, valueA, valueB } = values;
|
|
163
|
+
if (valueA + valueB == 0) return [Infinity, Infinity];
|
|
164
|
+
const safetyMargin = await this.getSafetyMargin();
|
|
165
|
+
const liquidationPenalty = await this.getLiquidationPenalty();
|
|
166
|
+
const actualCollateral = valueCollateral / liquidationPenalty;
|
|
167
|
+
const rad = Math.sqrt(actualCollateral ** 2 - 4 * valueA * valueB);
|
|
168
|
+
if (!rad) return [0, 0];
|
|
169
|
+
const t = (actualCollateral + rad) / (2 * Math.sqrt(safetyMargin));
|
|
170
|
+
let priceSwingA = (t / valueA) ** 2;
|
|
171
|
+
let priceSwingB = (t / valueB) ** 2;
|
|
172
|
+
return [priceSwingA, priceSwingB];
|
|
176
173
|
}
|
|
177
|
-
getLiquidationPricesGivenValues(values) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return !this.account.getOnchain().priceInverted ? [currentPrice / priceSwingB, currentPrice * priceSwingA] : [currentPrice / priceSwingA, currentPrice * priceSwingB];
|
|
182
|
-
});
|
|
174
|
+
public async getLiquidationPricesGivenValues(values: Values) : Promise<[number, number]> {
|
|
175
|
+
const currentPrice = await this.lendingPool.getTWAPPrice();
|
|
176
|
+
const [priceSwingA, priceSwingB] = await this.getLiquidationPriceSwingsGivenValues(values);
|
|
177
|
+
return !this.account.getOnchain().priceInverted ? [currentPrice / priceSwingB, currentPrice * priceSwingA] : [currentPrice / priceSwingA, currentPrice * priceSwingB];
|
|
183
178
|
}
|
|
184
|
-
getLiquidationPriceSwings(changes) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const values = yield this.getValues(changes);
|
|
189
|
-
return this.getLiquidationPriceSwingsGivenValues(values);
|
|
190
|
-
});
|
|
179
|
+
public async getLiquidationPriceSwings(changes?: Changes) {
|
|
180
|
+
if (!changes) changes = NO_CHANGES;
|
|
181
|
+
const values = await this.getValues(changes);
|
|
182
|
+
return this.getLiquidationPriceSwingsGivenValues(values);
|
|
191
183
|
}
|
|
184
|
+
public async getLiquidationPrices(changes?: Changes) {
|
|
185
|
+
if (!changes) changes = NO_CHANGES;
|
|
186
|
+
const values = await this.getValues(changes);
|
|
187
|
+
return this.getLiquidationPricesGivenValues(values);
|
|
188
|
+
}*/
|
|
192
189
|
getLiquidationPrices(changes) {
|
|
193
190
|
return __awaiter(this, void 0, void 0, function* () {
|
|
194
191
|
if (!changes)
|
|
195
192
|
changes = onchainTypes_1.NO_CHANGES;
|
|
196
|
-
const
|
|
197
|
-
|
|
193
|
+
const collateralAmount = (yield this.getCollateral().getDeposited()) + changes.changeCollateral;
|
|
194
|
+
const debtA = (yield this.getBorrowableA().getBorrowed()) + changes.changeBorrowedA;
|
|
195
|
+
const debtB = (yield this.getBorrowableB().getBorrowed()) + changes.changeBorrowedB;
|
|
196
|
+
const safetyMargin = yield this.getSafetyMargin();
|
|
197
|
+
const liquidationPenalty = yield this.getLiquidationPenalty();
|
|
198
|
+
const actualCollateral = collateralAmount / liquidationPenalty;
|
|
199
|
+
const reservesRatio = yield this.lendingPool.getReservesValueRatio();
|
|
200
|
+
const [priceA, priceB] = yield this.lendingPool.getPriceDenomLP();
|
|
201
|
+
const collateralA = actualCollateral * reservesRatio / (1 + reservesRatio) / priceA;
|
|
202
|
+
const collateralB = actualCollateral / (1 + reservesRatio) / priceB;
|
|
203
|
+
let priceSwingA, priceSwingB;
|
|
204
|
+
if (factories_1.STABLE_FACTORIES.includes(this.lendingPool.getImpermaxFactory().getFactory())) {
|
|
205
|
+
priceSwingA = (0, lliquidity_math_1.solidlyStable_getLiquidatableXPriceDecrease)(collateralA, collateralB, debtA, debtB) * safetyMargin;
|
|
206
|
+
priceSwingB = (0, lliquidity_math_1.solidlyStable_getLiquidatableXPriceDecrease)(collateralB, collateralA, debtB, debtA) * safetyMargin;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
priceSwingA = (0, lliquidity_math_1.uniswapV2_getLiquidatableXPriceDecrease)(collateralA, collateralB, debtA, debtB) * safetyMargin;
|
|
210
|
+
priceSwingB = (0, lliquidity_math_1.uniswapV2_getLiquidatableXPriceDecrease)(collateralB, collateralA, debtB, debtA) * safetyMargin;
|
|
211
|
+
}
|
|
212
|
+
const currentPrice = yield this.lendingPool.getTWAPPrice();
|
|
213
|
+
return !this.account.getOnchain().priceInverted
|
|
214
|
+
? [currentPrice * priceSwingA, currentPrice / priceSwingB]
|
|
215
|
+
: [currentPrice * priceSwingB, currentPrice / priceSwingA];
|
|
198
216
|
});
|
|
199
217
|
}
|
|
200
218
|
// Max Leverage
|
|
@@ -39,6 +39,8 @@ export default class OnchainLendingPool {
|
|
|
39
39
|
getPriceDenomLP(): Promise<[number, number]>;
|
|
40
40
|
getMarketPriceDenomLP(): Promise<[number, number]>;
|
|
41
41
|
getMarketPrice(): Promise<number>;
|
|
42
|
+
private initializeReservesValueRatio;
|
|
43
|
+
getReservesValueRatio(): Promise<number>;
|
|
42
44
|
private initializeTWAPPrice;
|
|
43
45
|
getTWAPPrice(): Promise<number>;
|
|
44
46
|
private initializeStakedLPExchangeRate;
|
|
@@ -16,7 +16,7 @@ const types_1 = require("../../../config/types");
|
|
|
16
16
|
const onchainCollateral_1 = __importDefault(require("./onchainCollateral"));
|
|
17
17
|
const onchainBorrowable_1 = __importDefault(require("./onchainBorrowable"));
|
|
18
18
|
const factories_1 = require("../../../config/factories");
|
|
19
|
-
const
|
|
19
|
+
const lliquidity_math_1 = require("../../../utils/lliquidity-math");
|
|
20
20
|
class OnchainLendingPool {
|
|
21
21
|
constructor(impermaxFactory, pairAddress) {
|
|
22
22
|
this.cache = {};
|
|
@@ -182,12 +182,98 @@ class OnchainLendingPool {
|
|
|
182
182
|
const [reserve0, reserve1] = yield this.getReserves();
|
|
183
183
|
const priceInverted = this.impermaxFactory.getOnchain().priceInverted;
|
|
184
184
|
if (factories_1.STABLE_FACTORIES.includes(this.impermaxFactory.getFactory()))
|
|
185
|
-
return (0,
|
|
185
|
+
return (0, lliquidity_math_1.solidlyStable_getPriceFromReserves)(reserve0, reserve1, priceInverted);
|
|
186
186
|
else
|
|
187
|
-
return (0,
|
|
187
|
+
return (0, lliquidity_math_1.uniswapV2_getPriceFromReserves)(reserve0, reserve1, priceInverted);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/*
|
|
191
|
+
// TWAP Reserves
|
|
192
|
+
// NON VA BENE, voglio tornare le riserve dello stakedLPToken o di tutto? DIPORCO
|
|
193
|
+
private async initializeTWAPReserves() : Promise<[number, number] | null> {
|
|
194
|
+
try {
|
|
195
|
+
const collateral = await this.getCollateral().getPoolToken();
|
|
196
|
+
const decimalsA = await this.getBorrowableA().getDecimals();
|
|
197
|
+
const decimalsB = await this.getBorrowableB().getDecimals();
|
|
198
|
+
|
|
199
|
+
if (STABLE_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
200
|
+
const { reserve0, reserve1 } = await collateral.methods.getReserves().call();
|
|
201
|
+
return [
|
|
202
|
+
reserve0 / Math.pow(10, decimalsA),
|
|
203
|
+
reserve1 / Math.pow(10, decimalsB)
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const [reserve0, reserve1] = await this.getReserves();
|
|
208
|
+
const currentPrice = uniswapV2_getPriceFromReserves(reserve0, reserve1);
|
|
209
|
+
let TWAPprice;
|
|
210
|
+
if (SOLIDEX_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
211
|
+
TWAPprice = await collateral.methods.getTwapPrice112x112().call();
|
|
212
|
+
} else {
|
|
213
|
+
TWAPprice = (await this.impermaxFactory.getSimpleUniswapOracle().methods.getResult(this.pairAddress).call()).price;
|
|
214
|
+
}
|
|
215
|
+
TWAPprice = TWAPprice / 2**112 * Math.pow(10, decimalsA) / Math.pow(10, decimalsB);
|
|
216
|
+
|
|
217
|
+
const adj = Math.sqrt(currentPrice / TWAPprice);
|
|
218
|
+
return [
|
|
219
|
+
reserve0 * adj,
|
|
220
|
+
reserve1 / adj,
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
catch (e) {
|
|
224
|
+
// Oracle is not initialized yet
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
public async getTWAPReserves() : Promise<[number, number] | null> {
|
|
229
|
+
if (!this.cache.TWAPReserves) this.cache.TWAPReserves = this.initializeTWAPReserves();
|
|
230
|
+
return this.cache.TWAPReserves;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// TWAP Price
|
|
234
|
+
private async initializeTWAPPrice() : Promise<number> {
|
|
235
|
+
const TWAPReserves = await this.getTWAPReserves();
|
|
236
|
+
if (!TWAPReserves) return 0;
|
|
237
|
+
const reserve0 = TWAPReserves[0];
|
|
238
|
+
const reserve1 = TWAPReserves[1];
|
|
239
|
+
|
|
240
|
+
if (STABLE_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
241
|
+
return solidlyStable_getPriceFromReserves(reserve0, reserve1);
|
|
242
|
+
} else {
|
|
243
|
+
return uniswapV2_getPriceFromReserves(reserve0, reserve1);
|
|
244
|
+
}
|
|
245
|
+
}*/
|
|
246
|
+
// Value of reserveA / reserveB
|
|
247
|
+
initializeReservesValueRatio() {
|
|
248
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
249
|
+
if (factories_1.STABLE_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
250
|
+
const collateral = yield this.getCollateral().getPoolToken();
|
|
251
|
+
const decimalsA = yield this.getBorrowableA().getDecimals();
|
|
252
|
+
const decimalsB = yield this.getBorrowableB().getDecimals();
|
|
253
|
+
const { twapReserve0, twapReserve1 } = yield collateral.methods.getTwapReserves().call();
|
|
254
|
+
const [price0, price1] = yield this.getPriceDenomLP();
|
|
255
|
+
return twapReserve0 * price0 / (twapReserve1 * price1);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
return 1;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
getReservesValueRatio() {
|
|
263
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
264
|
+
if (factories_1.STABLE_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
265
|
+
const collateral = yield this.getCollateral().getPoolToken();
|
|
266
|
+
const decimalsA = yield this.getBorrowableA().getDecimals();
|
|
267
|
+
const decimalsB = yield this.getBorrowableB().getDecimals();
|
|
268
|
+
const { twapReserve0, twapReserve1 } = yield collateral.methods.getTwapReserves().call();
|
|
269
|
+
const [price0, price1] = yield this.getPriceDenomLP();
|
|
270
|
+
return twapReserve0 * price0 / (twapReserve1 * price1);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
return 1;
|
|
274
|
+
}
|
|
188
275
|
});
|
|
189
276
|
}
|
|
190
|
-
// TWAP Price
|
|
191
277
|
initializeTWAPPrice() {
|
|
192
278
|
return __awaiter(this, void 0, void 0, function* () {
|
|
193
279
|
try {
|
|
@@ -196,7 +282,7 @@ class OnchainLendingPool {
|
|
|
196
282
|
const decimalsB = yield this.getBorrowableB().getDecimals();
|
|
197
283
|
if (factories_1.STABLE_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
198
284
|
const { twapReserve0, twapReserve1 } = yield collateral.methods.getTwapReserves().call();
|
|
199
|
-
return (0,
|
|
285
|
+
return (0, lliquidity_math_1.solidlyStable_getPriceFromReserves)(twapReserve0 / Math.pow(10, decimalsA), twapReserve1 / Math.pow(10, decimalsB));
|
|
200
286
|
}
|
|
201
287
|
let price;
|
|
202
288
|
if (factories_1.SOLIDEX_FACTORIES.includes(this.impermaxFactory.getFactory())) {
|
|
@@ -55,6 +55,7 @@ class OnchainInteractionsLendingPool {
|
|
|
55
55
|
const currentLeverage = yield accountLendingPool.getLeverage();
|
|
56
56
|
const collateralValue = yield accountLendingPool.getCollateral().getDeposited();
|
|
57
57
|
const changeCollateralValue = (collateralValue * leverage / currentLeverage - collateralValue) * adjustFactor;
|
|
58
|
+
// TODO wrong methodology, it's better to use the reserve ratio
|
|
58
59
|
const valueForEach = changeCollateralValue / 2;
|
|
59
60
|
const bAmountA = priceA > 0 ? valueForEach / priceA : 0;
|
|
60
61
|
const bAmountB = priceB > 0 ? valueForEach / priceB : 0;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare function uniswapV2_getPriceFromReserves(x: number, y: number, priceInverted?: boolean): number;
|
|
2
|
+
/**
|
|
3
|
+
* Find liquidation threshold given X/Y price decrease
|
|
4
|
+
* Returns a price ratio in the [0,1] range
|
|
5
|
+
*/
|
|
6
|
+
export declare function uniswapV2_getLiquidatableXPriceDecrease(x0: number, y0: number, debtX: number, debtY: number): number;
|
|
7
|
+
/**
|
|
8
|
+
* Calculate X/Y price
|
|
9
|
+
*/
|
|
10
|
+
export declare function solidlyStable_getPriceFromReserves(x: number, y: number, priceInverted?: boolean): number;
|
|
11
|
+
export declare function solidlyStable_k(x: number, y: number): number;
|
|
12
|
+
/**
|
|
13
|
+
* Calculate output from reserves y given input from x
|
|
14
|
+
*/
|
|
15
|
+
export declare function solidlyStable_yOut(xIn: number, x0: number, y0: number): number;
|
|
16
|
+
export declare function solidlyStable_getEquityValue(x: number, y: number, debtX: number, debtY: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Find xIn input amount that would bring the equity to negative
|
|
19
|
+
*/
|
|
20
|
+
export declare function solidlyStable_getXInMargin(x0: number, y0: number, debtX: number, debtY: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* Find liquidation threshold given X/Y price decrease
|
|
23
|
+
* Returns a price ratio in the [0,1] range
|
|
24
|
+
*/
|
|
25
|
+
export declare function solidlyStable_getLiquidatableXPriceDecrease(x0: number, y0: number, debtX: number, debtY: number): number;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.solidlyStable_getLiquidatableXPriceDecrease = exports.solidlyStable_getXInMargin = exports.solidlyStable_getEquityValue = exports.solidlyStable_yOut = exports.solidlyStable_k = exports.solidlyStable_getPriceFromReserves = exports.uniswapV2_getLiquidatableXPriceDecrease = exports.uniswapV2_getPriceFromReserves = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Calculate X/Y price
|
|
6
|
+
*/
|
|
7
|
+
const assert = require("assert");
|
|
8
|
+
function uniswapV2_getPriceFromReserves(x, y, priceInverted = false) {
|
|
9
|
+
const price = y / x;
|
|
10
|
+
return !priceInverted ? price : 1 / price;
|
|
11
|
+
}
|
|
12
|
+
exports.uniswapV2_getPriceFromReserves = uniswapV2_getPriceFromReserves;
|
|
13
|
+
/**
|
|
14
|
+
* Find liquidation threshold given X/Y price decrease
|
|
15
|
+
* Returns a price ratio in the [0,1] range
|
|
16
|
+
*/
|
|
17
|
+
function uniswapV2_getLiquidatableXPriceDecrease(x0, y0, debtX, debtY) {
|
|
18
|
+
const k = x0 * y0;
|
|
19
|
+
const x = k / debtY * (1 + Math.sqrt(1 - debtY * debtX / k));
|
|
20
|
+
if (x <= x0)
|
|
21
|
+
return 1;
|
|
22
|
+
if (x == Infinity)
|
|
23
|
+
return 0;
|
|
24
|
+
const y = k / x;
|
|
25
|
+
const price0 = uniswapV2_getPriceFromReserves(x0, y0);
|
|
26
|
+
const price = uniswapV2_getPriceFromReserves(x, y);
|
|
27
|
+
assert(price < price0, "Assertion error: uniswapV2_getLiquidatableXPriceDecrease price >= price0");
|
|
28
|
+
return price / price0;
|
|
29
|
+
}
|
|
30
|
+
exports.uniswapV2_getLiquidatableXPriceDecrease = uniswapV2_getLiquidatableXPriceDecrease;
|
|
31
|
+
/**
|
|
32
|
+
* Calculate X/Y price
|
|
33
|
+
*/
|
|
34
|
+
function solidlyStable_getPriceFromReserves(x, y, priceInverted = false) {
|
|
35
|
+
const N = 3 * Math.pow(x, 2) * y + Math.pow(y, 3);
|
|
36
|
+
const D = 3 * Math.pow(y, 2) * x + Math.pow(x, 3);
|
|
37
|
+
const price = N / D;
|
|
38
|
+
return !priceInverted ? price : 1 / price;
|
|
39
|
+
}
|
|
40
|
+
exports.solidlyStable_getPriceFromReserves = solidlyStable_getPriceFromReserves;
|
|
41
|
+
function solidlyStable_k(x, y) {
|
|
42
|
+
return Math.pow(x, 3) * y + Math.pow(y, 3) * x;
|
|
43
|
+
}
|
|
44
|
+
exports.solidlyStable_k = solidlyStable_k;
|
|
45
|
+
/**
|
|
46
|
+
* Calculate output from reserves y given input from x
|
|
47
|
+
*/
|
|
48
|
+
function solidlyStable_yOut(xIn, x0, y0) {
|
|
49
|
+
const k0 = solidlyStable_k(x0, y0);
|
|
50
|
+
const x = x0 + xIn;
|
|
51
|
+
let y = y0;
|
|
52
|
+
// search for new y
|
|
53
|
+
for (let i = 0; i < 16; i++) {
|
|
54
|
+
const yPrev = y;
|
|
55
|
+
const k = solidlyStable_k(x, y);
|
|
56
|
+
const d = 3 * x * Math.pow(y, 2) + Math.pow(x, 3);
|
|
57
|
+
if (k < k0) {
|
|
58
|
+
const dy = (k0 - k) / d;
|
|
59
|
+
y = y + dy;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const dy = (k - k0) / d;
|
|
63
|
+
y = y - dy;
|
|
64
|
+
}
|
|
65
|
+
if (Math.abs((y - yPrev) / y) < 1e-10) {
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return y0 - y;
|
|
70
|
+
}
|
|
71
|
+
exports.solidlyStable_yOut = solidlyStable_yOut;
|
|
72
|
+
function solidlyStable_getEquityValue(x, y, debtX, debtY) {
|
|
73
|
+
const price = solidlyStable_getPriceFromReserves(x, y);
|
|
74
|
+
const lpValue = x * price + y;
|
|
75
|
+
const debtValue = debtX * price + debtY;
|
|
76
|
+
return lpValue - debtValue;
|
|
77
|
+
}
|
|
78
|
+
exports.solidlyStable_getEquityValue = solidlyStable_getEquityValue;
|
|
79
|
+
/**
|
|
80
|
+
* Find xIn input amount that would bring the equity to negative
|
|
81
|
+
*/
|
|
82
|
+
function solidlyStable_getXInMargin(x0, y0, debtX, debtY) {
|
|
83
|
+
if (solidlyStable_getEquityValue(x0, y0, debtX, debtY) < 0)
|
|
84
|
+
return 0;
|
|
85
|
+
const STARTING_POINT = x0 * 1e9;
|
|
86
|
+
let xIn = STARTING_POINT;
|
|
87
|
+
let xInPrev = 0;
|
|
88
|
+
// binary search for xIn
|
|
89
|
+
for (let i = 0; i < 1000; i++) {
|
|
90
|
+
const x = x0 + xIn;
|
|
91
|
+
const y = y0 - solidlyStable_yOut(xIn, x0, y0);
|
|
92
|
+
const jump = Math.abs(xIn - xInPrev);
|
|
93
|
+
if (Math.abs(jump / x0) < 1e-10)
|
|
94
|
+
break;
|
|
95
|
+
xInPrev = xIn;
|
|
96
|
+
if (solidlyStable_getEquityValue(x, y, debtX, debtY) < 0)
|
|
97
|
+
xIn -= jump;
|
|
98
|
+
else {
|
|
99
|
+
if (xIn == STARTING_POINT)
|
|
100
|
+
return Infinity;
|
|
101
|
+
xIn += jump;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return xIn;
|
|
105
|
+
}
|
|
106
|
+
exports.solidlyStable_getXInMargin = solidlyStable_getXInMargin;
|
|
107
|
+
/**
|
|
108
|
+
* Find liquidation threshold given X/Y price decrease
|
|
109
|
+
* Returns a price ratio in the [0,1] range
|
|
110
|
+
*/
|
|
111
|
+
function solidlyStable_getLiquidatableXPriceDecrease(x0, y0, debtX, debtY) {
|
|
112
|
+
const xIn = solidlyStable_getXInMargin(x0, y0, debtX, debtY);
|
|
113
|
+
if (xIn == 0)
|
|
114
|
+
return 1;
|
|
115
|
+
if (xIn == Infinity)
|
|
116
|
+
return 0;
|
|
117
|
+
const x = x0 + xIn;
|
|
118
|
+
const y = y0 - solidlyStable_yOut(xIn, x0, y0);
|
|
119
|
+
const price0 = solidlyStable_getPriceFromReserves(x0, y0);
|
|
120
|
+
const price = solidlyStable_getPriceFromReserves(x, y);
|
|
121
|
+
assert(price < price0, "Assertion error: solidlyStable_getLiquidatableXPriceDecrease price >= price0");
|
|
122
|
+
return price / price0;
|
|
123
|
+
}
|
|
124
|
+
exports.solidlyStable_getLiquidatableXPriceDecrease = solidlyStable_getLiquidatableXPriceDecrease;
|
|
@@ -11,10 +11,9 @@ function getPriceFromReservesUniswapV2(x, y, priceInverted = true) {
|
|
|
11
11
|
}
|
|
12
12
|
exports.getPriceFromReservesUniswapV2 = getPriceFromReservesUniswapV2;
|
|
13
13
|
function getPriceFromReservesSolidlyStable(x, y, priceInverted = false) {
|
|
14
|
-
const N = 3 * x
|
|
15
|
-
const D = 3 * y
|
|
14
|
+
const N = 3 * Math.pow(x, 2) * y + Math.pow(y, 3);
|
|
15
|
+
const D = 3 * Math.pow(y, 2) * x + Math.pow(x, 3);
|
|
16
16
|
const price = N / D;
|
|
17
|
-
console.log(x, y, price);
|
|
18
17
|
return !priceInverted ? price : 1 / price;
|
|
19
18
|
}
|
|
20
19
|
exports.getPriceFromReservesSolidlyStable = getPriceFromReservesSolidlyStable;
|