@curvefi/llamalend-api 1.0.22-beta.1 → 1.0.22
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 +346 -0
- package/lib/llamalend.js +2 -2
- package/lib/mintMarkets/MintMarketTemplate.d.ts +21 -4
- package/lib/mintMarkets/MintMarketTemplate.js +52 -0
- package/lib/mintMarkets/interfaces/leverage.d.ts +90 -0
- package/lib/mintMarkets/interfaces/leverage.js +1 -0
- package/lib/mintMarkets/modules/index.d.ts +1 -0
- package/lib/mintMarkets/modules/index.js +1 -0
- package/lib/mintMarkets/modules/leverageV2.d.ts +131 -0
- package/lib/mintMarkets/modules/leverageV2.js +788 -0
- package/package.json +1 -1
- package/src/llamalend.ts +2 -2
- package/src/mintMarkets/MintMarketTemplate.ts +67 -4
- package/src/mintMarkets/interfaces/leverage.ts +104 -0
- package/src/mintMarkets/modules/index.ts +1 -0
- package/src/mintMarkets/modules/leverageV2.ts +932 -0
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import memoize from "memoizee";
|
|
11
|
+
import { _getAddress, parseUnits, BN, toBN, fromBN, ensureAllowance, hasAllowance, ensureAllowanceEstimateGas, formatUnits, smartNumber, formatNumber, _mulBy1_3, DIGas, } from "../../utils.js";
|
|
12
|
+
import { _getExpectedOdos, _getQuoteOdos, _assembleTxOdos } from "../../external-api.js";
|
|
13
|
+
/**
|
|
14
|
+
* LeverageV2 module for MintMarketTemplate
|
|
15
|
+
*/
|
|
16
|
+
export class LeverageV2Module {
|
|
17
|
+
constructor(market) {
|
|
18
|
+
this.swapDataCache = {};
|
|
19
|
+
this._getMarketId = () => {
|
|
20
|
+
if (!this.market.isDeleverageSupported) {
|
|
21
|
+
throw Error('For old markets use deprecatedLeverage');
|
|
22
|
+
}
|
|
23
|
+
return this.market.index;
|
|
24
|
+
};
|
|
25
|
+
this.hasLeverage = () => {
|
|
26
|
+
return this.llamalend.constants.ALIASES.leverage_zap !== this.llamalend.constants.ZERO_ADDRESS && this.market.isDeleverageSupported;
|
|
27
|
+
};
|
|
28
|
+
this.leverageCreateLoanMaxRecvAllRanges = memoize((userCollateral, userBorrowed) => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
this._checkLeverageZap();
|
|
30
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
31
|
+
const contract = this.llamalend.contracts[this.llamalend.constants.ALIASES.leverage_zap].multicallContract;
|
|
32
|
+
const oraclePriceBand = yield this.market.oraclePriceBand();
|
|
33
|
+
const pAvgApproxBN = BN(yield this.market.calcTickPrice(oraclePriceBand)); // upper tick of oracle price band
|
|
34
|
+
let pAvgBN = null;
|
|
35
|
+
const arrLength = this.market.maxBands - this.market.minBands + 1;
|
|
36
|
+
let maxLeverageCollateralBN = new Array(arrLength).fill(BN(0));
|
|
37
|
+
let _maxLeverageCollateral = new Array(arrLength).fill(BigInt(0));
|
|
38
|
+
let maxBorrowablePrevBN = new Array(arrLength).fill(BN(0));
|
|
39
|
+
let maxBorrowableBN = new Array(arrLength).fill(BN(0));
|
|
40
|
+
let _maxBorrowable = new Array(arrLength).fill(BigInt(0));
|
|
41
|
+
for (let i = 0; i < 5; i++) {
|
|
42
|
+
const pBN = pAvgBN !== null && pAvgBN !== void 0 ? pAvgBN : pAvgApproxBN;
|
|
43
|
+
maxBorrowablePrevBN = maxBorrowableBN;
|
|
44
|
+
const _userEffectiveCollateral = _userCollateral + fromBN(BN(userBorrowed).div(pBN), this.market.coinDecimals[1]);
|
|
45
|
+
const calls = [];
|
|
46
|
+
for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
|
|
47
|
+
const j = N - this.market.minBands;
|
|
48
|
+
calls.push(contract.max_borrowable(this.market.controller, _userEffectiveCollateral, _maxLeverageCollateral[j], N, fromBN(pBN)));
|
|
49
|
+
}
|
|
50
|
+
_maxBorrowable = (yield this.llamalend.multicallProvider.all(calls)).map((_mb) => _mb * BigInt(998) / BigInt(1000));
|
|
51
|
+
maxBorrowableBN = _maxBorrowable.map((_mb) => toBN(_mb, this.market.coinDecimals[0]));
|
|
52
|
+
const deltaBN = maxBorrowableBN.map((mb, l) => mb.minus(maxBorrowablePrevBN[l]).abs().div(mb));
|
|
53
|
+
if (BigNumber.max(...deltaBN).lt(0.0005)) {
|
|
54
|
+
maxBorrowableBN = maxBorrowablePrevBN;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
if (pAvgBN === null) {
|
|
58
|
+
const _y = BigInt(yield _getExpectedOdos.call(this.llamalend, this.market.coinAddresses[0], this.market.coinAddresses[1], _maxBorrowable[0], this.market.address));
|
|
59
|
+
const yBN = toBN(_y, this.market.coinDecimals[1]);
|
|
60
|
+
pAvgBN = maxBorrowableBN[0].div(yBN);
|
|
61
|
+
}
|
|
62
|
+
maxLeverageCollateralBN = maxBorrowableBN.map((mb) => mb.div(pAvgBN));
|
|
63
|
+
_maxLeverageCollateral = maxLeverageCollateralBN.map((mlc) => fromBN(mlc, this.market.coinDecimals[1]));
|
|
64
|
+
}
|
|
65
|
+
const userEffectiveCollateralBN = BN(userCollateral).plus(BN(userBorrowed).div(pAvgBN));
|
|
66
|
+
const res = {};
|
|
67
|
+
for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
|
|
68
|
+
const j = N - this.market.minBands;
|
|
69
|
+
res[N] = {
|
|
70
|
+
maxDebt: formatNumber(maxBorrowableBN[j].toString(), this.market.coinDecimals[0]),
|
|
71
|
+
maxTotalCollateral: formatNumber(maxLeverageCollateralBN[j].plus(userEffectiveCollateralBN).toString(), this.market.coinDecimals[1]),
|
|
72
|
+
userCollateral: formatNumber(userCollateral, this.market.coinDecimals[1]),
|
|
73
|
+
collateralFromUserBorrowed: formatNumber(BN(userBorrowed).div(pAvgBN).toString(), this.market.coinDecimals[1]),
|
|
74
|
+
collateralFromMaxDebt: formatNumber(maxLeverageCollateralBN[j].toString(), this.market.coinDecimals[1]),
|
|
75
|
+
maxLeverage: maxLeverageCollateralBN[j].plus(userEffectiveCollateralBN).div(userEffectiveCollateralBN).toString(),
|
|
76
|
+
avgPrice: pAvgBN.toString(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return res;
|
|
80
|
+
}), {
|
|
81
|
+
promise: true,
|
|
82
|
+
maxAge: 60 * 1000, // 1m
|
|
83
|
+
});
|
|
84
|
+
this._setSwapDataToCache = (inputCoinAddress, outputCoinAddress, _amount, slippage) => __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
let swapData = yield _getQuoteOdos.call(this.llamalend, inputCoinAddress, outputCoinAddress, _amount, this.market.address, true, slippage);
|
|
86
|
+
while (swapData.pathId == null) {
|
|
87
|
+
swapData = yield _getQuoteOdos.call(this.llamalend, inputCoinAddress, outputCoinAddress, _amount, this.market.address, true, slippage);
|
|
88
|
+
}
|
|
89
|
+
const key = `${inputCoinAddress}-${_amount}`;
|
|
90
|
+
this.swapDataCache[key] = Object.assign(Object.assign({}, swapData), { slippage });
|
|
91
|
+
});
|
|
92
|
+
this._getSwapDataFromCache = (inputCoinAddress, _amount) => {
|
|
93
|
+
const key = `${inputCoinAddress}-${_amount}`;
|
|
94
|
+
if (!(key in this.swapDataCache))
|
|
95
|
+
throw Error("You must call corresponding `expected` method first " +
|
|
96
|
+
"(leverage.createLoanExpectedCollateral, leverage.borrowMoreExpectedCollateral or leverage.repayExpectedBorrowed)");
|
|
97
|
+
return this.swapDataCache[key];
|
|
98
|
+
};
|
|
99
|
+
this._leverageExpectedCollateral = (userCollateral, userBorrowed, debt, user) => __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
101
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
102
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
103
|
+
// additionalCollateral = (userBorrowed / p) + leverageCollateral
|
|
104
|
+
const _additionalCollateral = BigInt(this._getSwapDataFromCache(this.market.coinAddresses[0], _debt + _userBorrowed).outAmounts[0]);
|
|
105
|
+
const _collateralFromDebt = _debt * BigInt(Math.pow(10, 18)) / (_debt + _userBorrowed) * _additionalCollateral / BigInt(Math.pow(10, 18));
|
|
106
|
+
const _collateralFromUserBorrowed = _additionalCollateral - _collateralFromDebt;
|
|
107
|
+
let _stateCollateral = BigInt(0);
|
|
108
|
+
if (user) {
|
|
109
|
+
const { _collateral, _stablecoin: _borrowed } = yield this.market._userState(user);
|
|
110
|
+
if (_borrowed > BigInt(0))
|
|
111
|
+
throw Error(`User ${user} is already in liquidation mode`);
|
|
112
|
+
_stateCollateral = _collateral;
|
|
113
|
+
}
|
|
114
|
+
const _totalCollateral = _userCollateral + _additionalCollateral;
|
|
115
|
+
const _futureStateCollateral = _stateCollateral + _totalCollateral;
|
|
116
|
+
const avgPrice = toBN(_debt + _userBorrowed, this.market.coinDecimals[0]).div(toBN(_additionalCollateral, this.market.coinDecimals[1])).toString();
|
|
117
|
+
return { _futureStateCollateral, _totalCollateral, _userCollateral, _collateralFromUserBorrowed, _collateralFromDebt, avgPrice };
|
|
118
|
+
});
|
|
119
|
+
this._leverageCalcN1 = memoize((userCollateral, userBorrowed, debt, range, user) => __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
if (range > 0)
|
|
121
|
+
this.market._checkRange(range);
|
|
122
|
+
let _stateDebt = BigInt(0);
|
|
123
|
+
if (user) {
|
|
124
|
+
const { _debt, _stablecoin: _borrowed } = yield this.market._userState(user);
|
|
125
|
+
const _N = yield this.market.userRange();
|
|
126
|
+
if (_borrowed > BigInt(0))
|
|
127
|
+
throw Error(`User ${user} is already in liquidation mode`);
|
|
128
|
+
_stateDebt = _debt;
|
|
129
|
+
if (range < 0)
|
|
130
|
+
range = Number(this.llamalend.formatUnits(_N, 0));
|
|
131
|
+
}
|
|
132
|
+
const { _futureStateCollateral } = yield this._leverageExpectedCollateral(userCollateral, userBorrowed, debt, user);
|
|
133
|
+
const _debt = _stateDebt + parseUnits(debt, this.market.coinDecimals[0]);
|
|
134
|
+
return yield this.llamalend.contracts[this.market.controller].contract.calculate_debt_n1(_futureStateCollateral, _debt, range, this.llamalend.constantOptions);
|
|
135
|
+
}), {
|
|
136
|
+
promise: true,
|
|
137
|
+
maxAge: 60 * 1000, // 1m
|
|
138
|
+
});
|
|
139
|
+
this._leverageCalcN1AllRanges = memoize((userCollateral, userBorrowed, debt, maxN) => __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
const { _futureStateCollateral } = yield this._leverageExpectedCollateral(userCollateral, userBorrowed, debt);
|
|
141
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
142
|
+
const calls = [];
|
|
143
|
+
for (let N = this.market.minBands; N <= maxN; N++) {
|
|
144
|
+
calls.push(this.llamalend.contracts[this.market.controller].multicallContract.calculate_debt_n1(_futureStateCollateral, _debt, N));
|
|
145
|
+
}
|
|
146
|
+
return yield this.llamalend.multicallProvider.all(calls);
|
|
147
|
+
}), {
|
|
148
|
+
promise: true,
|
|
149
|
+
maxAge: 60 * 1000, // 1m
|
|
150
|
+
});
|
|
151
|
+
// ---------------- LEVERAGE REPAY ----------------
|
|
152
|
+
this._leverageRepayExpectedBorrowed = (stateCollateral, userCollateral, userBorrowed) => {
|
|
153
|
+
this._checkLeverageZap();
|
|
154
|
+
const _stateCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]);
|
|
155
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
156
|
+
let _borrowedExpected = BigInt(0);
|
|
157
|
+
let _borrowedFromStateCollateral = BigInt(0);
|
|
158
|
+
let _borrowedFromUserCollateral = BigInt(0);
|
|
159
|
+
if (_stateCollateral + _userCollateral > BigInt(0)) {
|
|
160
|
+
_borrowedExpected = BigInt(this._getSwapDataFromCache(this.market.coinAddresses[1], _stateCollateral + _userCollateral).outAmounts[0]);
|
|
161
|
+
_borrowedFromStateCollateral = _stateCollateral * BigInt(Math.pow(10, 18)) / (_stateCollateral + _userCollateral) * _borrowedExpected / BigInt(Math.pow(10, 18));
|
|
162
|
+
_borrowedFromUserCollateral = _borrowedExpected - _borrowedFromStateCollateral;
|
|
163
|
+
}
|
|
164
|
+
const _totalBorrowed = _borrowedExpected + parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
165
|
+
const avgPrice = toBN(_borrowedExpected, this.market.coinDecimals[0]).div(toBN(_stateCollateral + _userCollateral, this.market.coinDecimals[1])).toString();
|
|
166
|
+
return { _totalBorrowed, _borrowedFromStateCollateral, _borrowedFromUserCollateral, avgPrice };
|
|
167
|
+
};
|
|
168
|
+
this.leverageRepayExpectedBorrowed = (stateCollateral_1, userCollateral_1, userBorrowed_1, ...args_1) => __awaiter(this, [stateCollateral_1, userCollateral_1, userBorrowed_1, ...args_1], void 0, function* (stateCollateral, userCollateral, userBorrowed, slippage = 0.1) {
|
|
169
|
+
this._checkLeverageZap();
|
|
170
|
+
const _stateCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]);
|
|
171
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
172
|
+
if (_stateCollateral + _userCollateral > BigInt(0)) {
|
|
173
|
+
yield this._setSwapDataToCache(this.market.coinAddresses[1], this.market.coinAddresses[0], _stateCollateral + _userCollateral, slippage);
|
|
174
|
+
}
|
|
175
|
+
const { _totalBorrowed, _borrowedFromStateCollateral, _borrowedFromUserCollateral, avgPrice } = this._leverageRepayExpectedBorrowed(stateCollateral, userCollateral, userBorrowed);
|
|
176
|
+
return {
|
|
177
|
+
totalBorrowed: formatUnits(_totalBorrowed, this.market.coinDecimals[0]),
|
|
178
|
+
borrowedFromStateCollateral: formatUnits(_borrowedFromStateCollateral, this.market.coinDecimals[0]),
|
|
179
|
+
borrowedFromUserCollateral: formatUnits(_borrowedFromUserCollateral, this.market.coinDecimals[0]),
|
|
180
|
+
userBorrowed: formatNumber(userBorrowed, this.market.coinDecimals[0]),
|
|
181
|
+
avgPrice,
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
this._leverageRepayBands = memoize((stateCollateral, userCollateral, userBorrowed, address) => __awaiter(this, void 0, void 0, function* () {
|
|
185
|
+
address = _getAddress.call(this.llamalend, address);
|
|
186
|
+
if (!(yield this.leverageRepayIsAvailable(stateCollateral, userCollateral, userBorrowed, address)))
|
|
187
|
+
return [parseUnits(0, 0), parseUnits(0, 0)];
|
|
188
|
+
const _stateRepayCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]);
|
|
189
|
+
const { _collateral: _stateCollateral, _debt: _stateDebt } = yield this.market._userState(address);
|
|
190
|
+
const _N = yield this.market.userRange();
|
|
191
|
+
if (_stateDebt == BigInt(0))
|
|
192
|
+
throw Error(`Loan for ${address} does not exist`);
|
|
193
|
+
if (_stateCollateral < _stateRepayCollateral)
|
|
194
|
+
throw Error(`Can't use more collateral than user's position has (${_stateRepayCollateral}) > ${_stateCollateral})`);
|
|
195
|
+
let _n1 = parseUnits(0, 0);
|
|
196
|
+
let _n2 = parseUnits(0, 0);
|
|
197
|
+
const { _totalBorrowed: _repayExpected } = this._leverageRepayExpectedBorrowed(stateCollateral, userCollateral, userBorrowed);
|
|
198
|
+
try {
|
|
199
|
+
_n1 = yield this.llamalend.contracts[this.market.controller].contract.calculate_debt_n1(_stateCollateral - _stateRepayCollateral, _stateDebt - _repayExpected, _N);
|
|
200
|
+
_n2 = _n1 + (BigInt(_N) - BigInt(1));
|
|
201
|
+
}
|
|
202
|
+
catch (_a) {
|
|
203
|
+
console.log("Full repayment");
|
|
204
|
+
}
|
|
205
|
+
return [_n2, _n1];
|
|
206
|
+
}), {
|
|
207
|
+
promise: true,
|
|
208
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
209
|
+
});
|
|
210
|
+
this.market = market;
|
|
211
|
+
this.llamalend = market.getLlamalend();
|
|
212
|
+
}
|
|
213
|
+
// ============ CREATE LOAN METHODS ============
|
|
214
|
+
// ---------------- LEVERAGE CREATE LOAN ----------------
|
|
215
|
+
userLoanExists() {
|
|
216
|
+
return __awaiter(this, arguments, void 0, function* (address = "") {
|
|
217
|
+
address = _getAddress.call(this.llamalend, address);
|
|
218
|
+
return yield this.llamalend.contracts[this.market.controller].contract.loan_exists(address, this.llamalend.constantOptions);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
_checkLeverageZap() {
|
|
222
|
+
if (!this.hasLeverage()) {
|
|
223
|
+
throw Error("This market does not support leverage");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
_get_k_effective_BN(N) {
|
|
227
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
228
|
+
// d_k_effective: uint256 = (1 - loan_discount) * sqrt((A-1)/A) / N
|
|
229
|
+
// k_effective = d_k_effective * sum_{0..N-1}(((A-1) / A)**k)
|
|
230
|
+
const { loan_discount } = yield this.market.statsParameters();
|
|
231
|
+
const A = this.market.A;
|
|
232
|
+
const A_BN = BN(A);
|
|
233
|
+
const A_ratio_BN = A_BN.minus(1).div(A_BN);
|
|
234
|
+
const d_k_effective_BN = BN(100).minus(loan_discount).div(100).times(A_ratio_BN.sqrt()).div(N);
|
|
235
|
+
let S = BN(0);
|
|
236
|
+
for (let n = 0; n < N; n++) {
|
|
237
|
+
S = S.plus(A_ratio_BN.pow(n));
|
|
238
|
+
}
|
|
239
|
+
return d_k_effective_BN.times(S);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
maxLeverage(N) {
|
|
243
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
244
|
+
// max_leverage = 1 / (k_effective - 1)
|
|
245
|
+
const k_effective_BN = yield this._get_k_effective_BN(N);
|
|
246
|
+
return BN(1).div(BN(1).minus(k_effective_BN)).toString();
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
leverageCreateLoanMaxRecv(userCollateral, userBorrowed, range) {
|
|
250
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
251
|
+
// max_borrowable = userCollateral / (1 / (k_effective * max_p_base) - 1 / p_avg)
|
|
252
|
+
this._checkLeverageZap();
|
|
253
|
+
if (range > 0)
|
|
254
|
+
this.market._checkRange(range);
|
|
255
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
256
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
257
|
+
const oraclePriceBand = yield this.market.oraclePriceBand();
|
|
258
|
+
let pAvgBN = BN(yield this.market.calcTickPrice(oraclePriceBand)); // upper tick of oracle price band
|
|
259
|
+
let maxBorrowablePrevBN = BN(0);
|
|
260
|
+
let maxBorrowableBN = BN(0);
|
|
261
|
+
let _userEffectiveCollateral = BigInt(0);
|
|
262
|
+
let _maxLeverageCollateral = BigInt(0);
|
|
263
|
+
const contract = this.llamalend.contracts[this.llamalend.constants.ALIASES.leverage_zap].contract;
|
|
264
|
+
for (let i = 0; i < 5; i++) {
|
|
265
|
+
maxBorrowablePrevBN = maxBorrowableBN;
|
|
266
|
+
_userEffectiveCollateral = _userCollateral + fromBN(BN(userBorrowed).div(pAvgBN), this.market.coinDecimals[1]);
|
|
267
|
+
let _maxBorrowable = yield contract.max_borrowable(this.market.controller, _userEffectiveCollateral, _maxLeverageCollateral, range, fromBN(pAvgBN));
|
|
268
|
+
_maxBorrowable = _maxBorrowable * BigInt(998) / BigInt(1000);
|
|
269
|
+
if (_maxBorrowable === BigInt(0))
|
|
270
|
+
break;
|
|
271
|
+
maxBorrowableBN = toBN(_maxBorrowable, this.market.coinDecimals[0]);
|
|
272
|
+
if (maxBorrowableBN.minus(maxBorrowablePrevBN).abs().div(maxBorrowablePrevBN).lt(0.0005)) {
|
|
273
|
+
maxBorrowableBN = maxBorrowablePrevBN;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
// additionalCollateral = (userBorrowed / p) + leverageCollateral
|
|
277
|
+
const _maxAdditionalCollateral = BigInt(yield _getExpectedOdos.call(this.llamalend, this.market.coinAddresses[0], this.market.coinAddresses[1], _maxBorrowable + _userBorrowed, this.market.address));
|
|
278
|
+
pAvgBN = maxBorrowableBN.plus(userBorrowed).div(toBN(_maxAdditionalCollateral, this.market.coinDecimals[1]));
|
|
279
|
+
_maxLeverageCollateral = _maxAdditionalCollateral - fromBN(BN(userBorrowed).div(pAvgBN), this.market.coinDecimals[1]);
|
|
280
|
+
}
|
|
281
|
+
const userEffectiveCollateralBN = maxBorrowableBN.gt(0) ? toBN(_userEffectiveCollateral, this.market.coinDecimals[1]) : BN(0);
|
|
282
|
+
const maxLeverageCollateralBN = toBN(_maxLeverageCollateral, this.market.coinDecimals[1]);
|
|
283
|
+
return {
|
|
284
|
+
maxDebt: formatNumber(maxBorrowableBN.toString(), this.market.coinDecimals[0]),
|
|
285
|
+
maxTotalCollateral: formatNumber(maxLeverageCollateralBN.plus(userEffectiveCollateralBN).toString(), this.market.coinDecimals[1]),
|
|
286
|
+
userCollateral: formatNumber(userCollateral, this.market.coinDecimals[1]),
|
|
287
|
+
collateralFromUserBorrowed: formatNumber(BN(userBorrowed).div(pAvgBN).toString(), this.market.coinDecimals[1]),
|
|
288
|
+
collateralFromMaxDebt: formatNumber(maxLeverageCollateralBN.toString(), this.market.coinDecimals[1]),
|
|
289
|
+
maxLeverage: maxLeverageCollateralBN.plus(userEffectiveCollateralBN).div(userEffectiveCollateralBN).toString(),
|
|
290
|
+
avgPrice: pAvgBN.toString(),
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
leverageCreateLoanExpectedCollateral(userCollateral_1, userBorrowed_1, debt_1) {
|
|
295
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, debt, slippage = 0.1) {
|
|
296
|
+
this._checkLeverageZap();
|
|
297
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
298
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
299
|
+
yield this._setSwapDataToCache(this.market.coinAddresses[0], this.market.coinAddresses[1], _debt + _userBorrowed, slippage);
|
|
300
|
+
const { _totalCollateral, _userCollateral, _collateralFromUserBorrowed, _collateralFromDebt, avgPrice } = yield this._leverageExpectedCollateral(userCollateral, userBorrowed, debt);
|
|
301
|
+
return {
|
|
302
|
+
totalCollateral: formatUnits(_totalCollateral, this.market.coinDecimals[1]),
|
|
303
|
+
userCollateral: formatUnits(_userCollateral, this.market.coinDecimals[1]),
|
|
304
|
+
collateralFromUserBorrowed: formatUnits(_collateralFromUserBorrowed, this.market.coinDecimals[1]),
|
|
305
|
+
collateralFromDebt: formatUnits(_collateralFromDebt, this.market.coinDecimals[1]),
|
|
306
|
+
leverage: toBN(_collateralFromDebt + _userCollateral + _collateralFromUserBorrowed, this.market.coinDecimals[1])
|
|
307
|
+
.div(toBN(_userCollateral + _collateralFromUserBorrowed, this.market.coinDecimals[1])).toString(),
|
|
308
|
+
avgPrice,
|
|
309
|
+
};
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
leverageCreateLoanPriceImpact(userBorrowed, debt) {
|
|
313
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
314
|
+
this._checkLeverageZap();
|
|
315
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
316
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
317
|
+
return this._getSwapDataFromCache(this.market.coinAddresses[0], _debt + _userBorrowed).priceImpact.toString();
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
leverageCreateLoanMaxRange(userCollateral, userBorrowed, debt) {
|
|
321
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
322
|
+
this._checkLeverageZap();
|
|
323
|
+
const maxRecv = yield this.leverageCreateLoanMaxRecvAllRanges(userCollateral, userBorrowed);
|
|
324
|
+
for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
|
|
325
|
+
if (BN(debt).gt(maxRecv[N].maxDebt))
|
|
326
|
+
return N - 1;
|
|
327
|
+
}
|
|
328
|
+
return this.market.maxBands;
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
_leverageBands(userCollateral, userBorrowed, debt, range, user) {
|
|
332
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
333
|
+
const _n1 = yield this._leverageCalcN1(userCollateral, userBorrowed, debt, range, user);
|
|
334
|
+
if (range < 0) {
|
|
335
|
+
const N = yield this.market.userRange();
|
|
336
|
+
range = Number(N);
|
|
337
|
+
}
|
|
338
|
+
const _n2 = _n1 + BigInt(range - 1);
|
|
339
|
+
return [_n2, _n1];
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
_leverageCreateLoanBandsAllRanges(userCollateral, userBorrowed, debt) {
|
|
343
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
344
|
+
const maxN = yield this.leverageCreateLoanMaxRange(userCollateral, userBorrowed, debt);
|
|
345
|
+
const _n1_arr = yield this._leverageCalcN1AllRanges(userCollateral, userBorrowed, debt, maxN);
|
|
346
|
+
const _n2_arr = [];
|
|
347
|
+
for (let N = this.market.minBands; N <= maxN; N++) {
|
|
348
|
+
_n2_arr.push(_n1_arr[N - this.market.minBands] + BigInt(N - 1));
|
|
349
|
+
}
|
|
350
|
+
const _bands = {};
|
|
351
|
+
for (let N = this.market.minBands; N <= maxN; N++) {
|
|
352
|
+
_bands[N] = [_n2_arr[N - this.market.minBands], _n1_arr[N - this.market.minBands]];
|
|
353
|
+
}
|
|
354
|
+
return _bands;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
leverageCreateLoanBands(userCollateral, userBorrowed, debt, range) {
|
|
358
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
359
|
+
this._checkLeverageZap();
|
|
360
|
+
const [_n2, _n1] = yield this._leverageBands(userCollateral, userBorrowed, debt, range);
|
|
361
|
+
return [Number(_n2), Number(_n1)];
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
leverageCreateLoanBandsAllRanges(userCollateral, userBorrowed, debt) {
|
|
365
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
366
|
+
this._checkLeverageZap();
|
|
367
|
+
const _bands = yield this._leverageCreateLoanBandsAllRanges(userCollateral, userBorrowed, debt);
|
|
368
|
+
const bands = {};
|
|
369
|
+
for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
|
|
370
|
+
if (_bands[N]) {
|
|
371
|
+
bands[N] = _bands[N].map(Number);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
bands[N] = null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return bands;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
leverageCreateLoanPrices(userCollateral, userBorrowed, debt, range) {
|
|
381
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
382
|
+
this._checkLeverageZap();
|
|
383
|
+
const [_n2, _n1] = yield this._leverageBands(userCollateral, userBorrowed, debt, range);
|
|
384
|
+
return yield this.market._getPrices(_n2, _n1);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
leverageCreateLoanPricesAllRanges(userCollateral, userBorrowed, debt) {
|
|
388
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
389
|
+
this._checkLeverageZap();
|
|
390
|
+
const _bands = yield this._leverageCreateLoanBandsAllRanges(userCollateral, userBorrowed, debt);
|
|
391
|
+
const prices = {};
|
|
392
|
+
for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
|
|
393
|
+
if (_bands[N]) {
|
|
394
|
+
prices[N] = yield this.market._calcPrices(..._bands[N]);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
prices[N] = null;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return prices;
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
_leverageHealth(userCollateral_1, userBorrowed_1, dDebt_1, range_1, full_1) {
|
|
404
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, dDebt, range, full, user = this.llamalend.constants.ZERO_ADDRESS) {
|
|
405
|
+
if (range > 0)
|
|
406
|
+
this.market._checkRange(range);
|
|
407
|
+
const { _totalCollateral } = yield this._leverageExpectedCollateral(userCollateral, userBorrowed, dDebt, user);
|
|
408
|
+
const { _stablecoin: _borrowed } = yield this.market._userState(user);
|
|
409
|
+
const _N = yield this.market.userRange();
|
|
410
|
+
if (_borrowed > BigInt(0))
|
|
411
|
+
throw Error(`User ${user} is already in liquidation mode`);
|
|
412
|
+
if (range < 0)
|
|
413
|
+
range = Number(this.llamalend.formatUnits(_N, 0));
|
|
414
|
+
const _dDebt = parseUnits(dDebt, this.market.coinDecimals[0]);
|
|
415
|
+
const contract = this.llamalend.contracts[this.market.controller].contract;
|
|
416
|
+
let _health = yield contract.health_calculator(user, _totalCollateral, _dDebt, full, range, this.llamalend.constantOptions);
|
|
417
|
+
_health = _health * BigInt(100);
|
|
418
|
+
return formatUnits(_health);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
leverageCreateLoanHealth(userCollateral_1, userBorrowed_1, debt_1, range_1) {
|
|
422
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, debt, range, full = true) {
|
|
423
|
+
this._checkLeverageZap();
|
|
424
|
+
return yield this._leverageHealth(userCollateral, userBorrowed, debt, range, full);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
leverageCreateLoanIsApproved(userCollateral, userBorrowed) {
|
|
428
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
429
|
+
this._checkLeverageZap();
|
|
430
|
+
const collateralAllowance = yield hasAllowance.call(this.llamalend, [this.market.coinAddresses[1]], [userCollateral], this.llamalend.signerAddress, this.market.controller);
|
|
431
|
+
const borrowedAllowance = yield hasAllowance.call(this.llamalend, [this.market.coinAddresses[0]], [userBorrowed], this.llamalend.signerAddress, this.llamalend.constants.ALIASES.leverage_zap);
|
|
432
|
+
return collateralAllowance && borrowedAllowance;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
leverageCreateLoanApproveEstimateGas(userCollateral, userBorrowed) {
|
|
436
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
437
|
+
this._checkLeverageZap();
|
|
438
|
+
const collateralGas = yield ensureAllowanceEstimateGas.call(this.llamalend, [this.market.coinAddresses[1]], [userCollateral], this.market.controller);
|
|
439
|
+
const borrowedGas = yield ensureAllowanceEstimateGas.call(this.llamalend, [this.market.coinAddresses[0]], [userBorrowed], this.llamalend.constants.ALIASES.leverage_zap);
|
|
440
|
+
if (Array.isArray(collateralGas) && Array.isArray(borrowedGas)) {
|
|
441
|
+
return [collateralGas[0] + borrowedGas[0], collateralGas[1] + borrowedGas[1]];
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
return collateralGas + borrowedGas;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
leverageCreateLoanApprove(userCollateral, userBorrowed) {
|
|
449
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
450
|
+
this._checkLeverageZap();
|
|
451
|
+
const collateralApproveTx = yield ensureAllowance.call(this.llamalend, [this.market.coinAddresses[1]], [userCollateral], this.market.controller);
|
|
452
|
+
const borrowedApproveTx = yield ensureAllowance.call(this.llamalend, [this.market.coinAddresses[0]], [userBorrowed], this.llamalend.constants.ALIASES.leverage_zap);
|
|
453
|
+
return [...collateralApproveTx, ...borrowedApproveTx];
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
leverageCreateLoanRouteImage(userBorrowed, debt) {
|
|
457
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
458
|
+
this._checkLeverageZap();
|
|
459
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
460
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
461
|
+
return this._getSwapDataFromCache(this.market.coinAddresses[0], _debt + _userBorrowed).pathVizImage;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
_leverageCreateLoan(userCollateral, userBorrowed, debt, range, slippage, estimateGas) {
|
|
465
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
466
|
+
if (yield this.userLoanExists())
|
|
467
|
+
throw Error("Loan already created");
|
|
468
|
+
this.market._checkRange(range);
|
|
469
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
470
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
471
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
472
|
+
const swapData = this._getSwapDataFromCache(this.market.coinAddresses[0], _debt + _userBorrowed);
|
|
473
|
+
if (slippage !== swapData.slippage)
|
|
474
|
+
throw Error(`You must call leverage.createLoanExpectedCollateral() with slippage=${slippage} first`);
|
|
475
|
+
const calldata = yield _assembleTxOdos.call(this.llamalend, swapData.pathId);
|
|
476
|
+
const contract = this.llamalend.contracts[this.market.controller].contract;
|
|
477
|
+
const gas = yield contract.create_loan_extended.estimateGas(_userCollateral, _debt, range, this.llamalend.constants.ALIASES.leverage_zap, [1, parseUnits(this._getMarketId(), 0), _userBorrowed], calldata, Object.assign({}, this.llamalend.constantOptions));
|
|
478
|
+
if (estimateGas)
|
|
479
|
+
return smartNumber(gas);
|
|
480
|
+
yield this.llamalend.updateFeeData();
|
|
481
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
482
|
+
return (yield contract.create_loan_extended(_userCollateral, _debt, range, this.llamalend.constants.ALIASES.leverage_zap, [1, parseUnits(this._getMarketId(), 0), _userBorrowed], calldata, Object.assign(Object.assign({}, this.llamalend.options), { gasLimit }))).hash;
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
leverageCreateLoanEstimateGas(userCollateral_1, userBorrowed_1, debt_1, range_1) {
|
|
486
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, debt, range, slippage = 0.1) {
|
|
487
|
+
this._checkLeverageZap();
|
|
488
|
+
if (!(yield this.leverageCreateLoanIsApproved(userCollateral, userBorrowed)))
|
|
489
|
+
throw Error("Approval is needed for gas estimation");
|
|
490
|
+
return yield this._leverageCreateLoan(userCollateral, userBorrowed, debt, range, slippage, true);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
leverageCreateLoan(userCollateral_1, userBorrowed_1, debt_1, range_1) {
|
|
494
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, debt, range, slippage = 0.1) {
|
|
495
|
+
this._checkLeverageZap();
|
|
496
|
+
yield this.leverageCreateLoanApprove(userCollateral, userBorrowed);
|
|
497
|
+
return yield this._leverageCreateLoan(userCollateral, userBorrowed, debt, range, slippage, false);
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
// ---------------- LEVERAGE BORROW MORE ----------------
|
|
501
|
+
leverageBorrowMoreMaxRecv(userCollateral_1, userBorrowed_1) {
|
|
502
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, address = "") {
|
|
503
|
+
// max_borrowable = userCollateral / (1 / (k_effective * max_p_base) - 1 / p_avg)
|
|
504
|
+
this._checkLeverageZap();
|
|
505
|
+
address = _getAddress.call(this.llamalend, address);
|
|
506
|
+
const { _collateral: _stateCollateral, _stablecoin: _stateBorrowed, _debt: _stateDebt } = yield this.market._userState(address);
|
|
507
|
+
const _N = yield this.market.userRange();
|
|
508
|
+
if (_stateBorrowed > BigInt(0))
|
|
509
|
+
throw Error(`User ${address} is already in liquidation mode`);
|
|
510
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
511
|
+
const controllerContract = this.llamalend.contracts[this.market.controller].contract;
|
|
512
|
+
const _borrowedFromStateCollateral = (yield controllerContract.max_borrowable(_stateCollateral, _N, _stateDebt, this.llamalend.constantOptions)) - _stateDebt;
|
|
513
|
+
const _userBorrowed = _borrowedFromStateCollateral + parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
514
|
+
userBorrowed = formatUnits(_userBorrowed, this.market.coinDecimals[0]);
|
|
515
|
+
const oraclePriceBand = yield this.market.oraclePriceBand();
|
|
516
|
+
let pAvgBN = BN(yield this.market.calcTickPrice(oraclePriceBand)); // upper tick of oracle price band
|
|
517
|
+
let maxBorrowablePrevBN = BN(0);
|
|
518
|
+
let maxBorrowableBN = BN(0);
|
|
519
|
+
let _userEffectiveCollateral = BigInt(0);
|
|
520
|
+
let _maxLeverageCollateral = BigInt(0);
|
|
521
|
+
const contract = this.llamalend.contracts[this.llamalend.constants.ALIASES.leverage_zap].contract;
|
|
522
|
+
for (let i = 0; i < 5; i++) {
|
|
523
|
+
maxBorrowablePrevBN = maxBorrowableBN;
|
|
524
|
+
_userEffectiveCollateral = _userCollateral + fromBN(BN(userBorrowed).div(pAvgBN), this.market.coinDecimals[1]);
|
|
525
|
+
let _maxBorrowable = yield contract.max_borrowable(this.market.controller, _userEffectiveCollateral, _maxLeverageCollateral, _N, fromBN(pAvgBN));
|
|
526
|
+
_maxBorrowable = _maxBorrowable * BigInt(998) / BigInt(1000);
|
|
527
|
+
if (_maxBorrowable === BigInt(0))
|
|
528
|
+
break;
|
|
529
|
+
maxBorrowableBN = toBN(_maxBorrowable, this.market.coinDecimals[0]);
|
|
530
|
+
if (maxBorrowableBN.minus(maxBorrowablePrevBN).abs().div(maxBorrowablePrevBN).lt(0.0005)) {
|
|
531
|
+
maxBorrowableBN = maxBorrowablePrevBN;
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
// additionalCollateral = (userBorrowed / p) + leverageCollateral
|
|
535
|
+
const _maxAdditionalCollateral = BigInt(yield _getExpectedOdos.call(this.llamalend, this.market.coinAddresses[0], this.market.coinAddresses[1], _maxBorrowable + _userBorrowed, this.market.address));
|
|
536
|
+
pAvgBN = maxBorrowableBN.plus(userBorrowed).div(toBN(_maxAdditionalCollateral, this.market.coinDecimals[1]));
|
|
537
|
+
_maxLeverageCollateral = _maxAdditionalCollateral - fromBN(BN(userBorrowed).div(pAvgBN), this.market.coinDecimals[1]);
|
|
538
|
+
}
|
|
539
|
+
if (maxBorrowableBN.eq(0))
|
|
540
|
+
_userEffectiveCollateral = BigInt(0);
|
|
541
|
+
const _maxTotalCollateral = _userEffectiveCollateral + _maxLeverageCollateral;
|
|
542
|
+
let _maxBorrowable = (yield controllerContract.max_borrowable(_stateCollateral + _maxTotalCollateral, _N, _stateDebt, this.llamalend.constantOptions)) - _stateDebt;
|
|
543
|
+
_maxBorrowable = _maxBorrowable * BigInt(998) / BigInt(1000);
|
|
544
|
+
return {
|
|
545
|
+
maxDebt: formatUnits(_maxBorrowable, this.market.coinDecimals[0]),
|
|
546
|
+
maxTotalCollateral: formatUnits(_maxTotalCollateral, this.market.coinDecimals[1]),
|
|
547
|
+
userCollateral: formatNumber(userCollateral, this.market.coinDecimals[1]),
|
|
548
|
+
collateralFromUserBorrowed: formatNumber(BN(userBorrowed).div(pAvgBN).toString(), this.market.coinDecimals[1]),
|
|
549
|
+
collateralFromMaxDebt: formatUnits(_maxLeverageCollateral, this.market.coinDecimals[1]),
|
|
550
|
+
avgPrice: pAvgBN.toString(),
|
|
551
|
+
};
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
leverageBorrowMoreExpectedCollateral(userCollateral_1, userBorrowed_1, dDebt_1) {
|
|
555
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, dDebt, slippage = 0.1, address = "") {
|
|
556
|
+
this._checkLeverageZap();
|
|
557
|
+
address = _getAddress.call(this.llamalend, address);
|
|
558
|
+
const _dDebt = parseUnits(dDebt, this.market.coinDecimals[0]);
|
|
559
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
560
|
+
yield this._setSwapDataToCache(this.market.coinAddresses[0], this.market.coinAddresses[1], _dDebt + _userBorrowed, slippage);
|
|
561
|
+
const { _totalCollateral, _userCollateral, _collateralFromUserBorrowed, _collateralFromDebt, avgPrice } = yield this._leverageExpectedCollateral(userCollateral, userBorrowed, dDebt, address);
|
|
562
|
+
return {
|
|
563
|
+
totalCollateral: formatUnits(_totalCollateral, this.market.coinDecimals[1]),
|
|
564
|
+
userCollateral: formatUnits(_userCollateral, this.market.coinDecimals[1]),
|
|
565
|
+
collateralFromUserBorrowed: formatUnits(_collateralFromUserBorrowed, this.market.coinDecimals[1]),
|
|
566
|
+
collateralFromDebt: formatUnits(_collateralFromDebt, this.market.coinDecimals[1]),
|
|
567
|
+
avgPrice,
|
|
568
|
+
};
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
leverageBorrowMorePriceImpact(userBorrowed, dDebt) {
|
|
572
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
573
|
+
this._checkLeverageZap();
|
|
574
|
+
const _dDebt = parseUnits(dDebt, this.market.coinDecimals[0]);
|
|
575
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
576
|
+
return this._getSwapDataFromCache(this.market.coinAddresses[0], _dDebt + _userBorrowed).priceImpact.toString();
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
leverageBorrowMoreBands(userCollateral_1, userBorrowed_1, dDebt_1) {
|
|
580
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, dDebt, address = "") {
|
|
581
|
+
address = _getAddress.call(this.llamalend, address);
|
|
582
|
+
this._checkLeverageZap();
|
|
583
|
+
const [_n2, _n1] = yield this._leverageBands(userCollateral, userBorrowed, dDebt, -1, address);
|
|
584
|
+
return [Number(_n2), Number(_n1)];
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
leverageBorrowMorePrices(userCollateral_1, userBorrowed_1, dDebt_1) {
|
|
588
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, dDebt, address = "") {
|
|
589
|
+
address = _getAddress.call(this.llamalend, address);
|
|
590
|
+
this._checkLeverageZap();
|
|
591
|
+
const [_n2, _n1] = yield this._leverageBands(userCollateral, userBorrowed, dDebt, -1, address);
|
|
592
|
+
return yield this.market._getPrices(_n2, _n1);
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
leverageBorrowMoreHealth(userCollateral_1, userBorrowed_1, dDebt_1) {
|
|
596
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, dDebt, full = true, address = "") {
|
|
597
|
+
this._checkLeverageZap();
|
|
598
|
+
address = _getAddress.call(this.llamalend, address);
|
|
599
|
+
return yield this._leverageHealth(userCollateral, userBorrowed, dDebt, -1, full, address);
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
leverageBorrowMoreRouteImage(userBorrowed, debt) {
|
|
603
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
604
|
+
this._checkLeverageZap();
|
|
605
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
606
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
607
|
+
return this._getSwapDataFromCache(this.market.coinAddresses[0], _debt + _userBorrowed).pathVizImage;
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
_leverageBorrowMore(userCollateral, userBorrowed, debt, slippage, estimateGas) {
|
|
611
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
612
|
+
if (!(yield this.userLoanExists()))
|
|
613
|
+
throw Error("Loan does not exist");
|
|
614
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
615
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
616
|
+
const _debt = parseUnits(debt, this.market.coinDecimals[0]);
|
|
617
|
+
const swapData = this._getSwapDataFromCache(this.market.coinAddresses[0], _debt + _userBorrowed);
|
|
618
|
+
if (slippage !== swapData.slippage)
|
|
619
|
+
throw Error(`You must call leverage.borrowMoreExpectedCollateral() with slippage=${slippage} first`);
|
|
620
|
+
const calldata = yield _assembleTxOdos.call(this.llamalend, swapData.pathId);
|
|
621
|
+
const contract = this.llamalend.contracts[this.market.controller].contract;
|
|
622
|
+
const gas = yield contract.borrow_more_extended.estimateGas(_userCollateral, _debt, this.llamalend.constants.ALIASES.leverage_zap, [1, parseUnits(this._getMarketId(), 0), _userBorrowed], calldata, Object.assign({}, this.llamalend.constantOptions));
|
|
623
|
+
if (estimateGas)
|
|
624
|
+
return smartNumber(gas);
|
|
625
|
+
yield this.llamalend.updateFeeData();
|
|
626
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
627
|
+
return (yield contract.borrow_more_extended(_userCollateral, _debt, this.llamalend.constants.ALIASES.leverage_zap, [1, parseUnits(this._getMarketId(), 0), _userBorrowed], calldata, Object.assign(Object.assign({}, this.llamalend.options), { gasLimit }))).hash;
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
leverageBorrowMoreEstimateGas(userCollateral_1, userBorrowed_1, debt_1) {
|
|
631
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, debt, slippage = 0.1) {
|
|
632
|
+
this._checkLeverageZap();
|
|
633
|
+
if (!(yield this.leverageCreateLoanIsApproved(userCollateral, userBorrowed)))
|
|
634
|
+
throw Error("Approval is needed for gas estimation");
|
|
635
|
+
return yield this._leverageBorrowMore(userCollateral, userBorrowed, debt, slippage, true);
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
leverageBorrowMore(userCollateral_1, userBorrowed_1, debt_1) {
|
|
639
|
+
return __awaiter(this, arguments, void 0, function* (userCollateral, userBorrowed, debt, slippage = 0.1) {
|
|
640
|
+
this._checkLeverageZap();
|
|
641
|
+
yield this.leverageCreateLoanApprove(userCollateral, userBorrowed);
|
|
642
|
+
return yield this._leverageBorrowMore(userCollateral, userBorrowed, debt, slippage, false);
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
leverageRepayPriceImpact(stateCollateral, userCollateral) {
|
|
646
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
647
|
+
this._checkLeverageZap();
|
|
648
|
+
const _stateCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]);
|
|
649
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
650
|
+
if (_stateCollateral + _userCollateral > BigInt(0)) {
|
|
651
|
+
return this._getSwapDataFromCache(this.market.coinAddresses[1], _stateCollateral + _userCollateral).priceImpact.toString();
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
return "0.0";
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
leverageRepayIsFull(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
659
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, address = "") {
|
|
660
|
+
this._checkLeverageZap();
|
|
661
|
+
address = _getAddress.call(this.llamalend, address);
|
|
662
|
+
const { _stablecoin: _stateBorrowed, _debt } = yield this.market._userState(address);
|
|
663
|
+
const { _totalBorrowed } = this._leverageRepayExpectedBorrowed(stateCollateral, userCollateral, userBorrowed);
|
|
664
|
+
return _stateBorrowed + _totalBorrowed > _debt;
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
leverageRepayIsAvailable(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
668
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, address = "") {
|
|
669
|
+
// 0. const { collateral, stablecoin, debt } = await this.userState(address);
|
|
670
|
+
// 1. maxCollateral for deleverage is collateral from line above.
|
|
671
|
+
// 2. If user is underwater (stablecoin > 0), only full repayment is available:
|
|
672
|
+
// await this.deleverageRepayStablecoins(deleverageCollateral) + stablecoin > debt
|
|
673
|
+
this._checkLeverageZap();
|
|
674
|
+
address = _getAddress.call(this.llamalend, address);
|
|
675
|
+
const { collateral, stablecoin: borrowed, debt } = yield this.market.userState(address);
|
|
676
|
+
// Loan does not exist
|
|
677
|
+
if (BN(debt).eq(0))
|
|
678
|
+
return false;
|
|
679
|
+
// Can't spend more than user has
|
|
680
|
+
if (BN(stateCollateral).gt(collateral))
|
|
681
|
+
return false;
|
|
682
|
+
// Only full repayment and closing the position is available if user is underwater+
|
|
683
|
+
if (BN(borrowed).gt(0))
|
|
684
|
+
return yield this.leverageRepayIsFull(stateCollateral, userCollateral, userBorrowed, address);
|
|
685
|
+
return true;
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
leverageRepayBands(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
689
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, address = "") {
|
|
690
|
+
this._checkLeverageZap();
|
|
691
|
+
const [_n2, _n1] = yield this._leverageRepayBands(stateCollateral, userCollateral, userBorrowed, address);
|
|
692
|
+
return [Number(_n2), Number(_n1)];
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
leverageRepayPrices(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
696
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, address = "") {
|
|
697
|
+
this._checkLeverageZap();
|
|
698
|
+
const [_n2, _n1] = yield this._leverageRepayBands(stateCollateral, userCollateral, userBorrowed, address);
|
|
699
|
+
return yield this.market._getPrices(_n2, _n1);
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
leverageRepayHealth(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
703
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, full = true, address = "") {
|
|
704
|
+
this._checkLeverageZap();
|
|
705
|
+
address = _getAddress.call(this.llamalend, address);
|
|
706
|
+
const { _stablecoin: _stateBorrowed, _debt } = yield this.market._userState(address);
|
|
707
|
+
const _N = yield this.market.userRange();
|
|
708
|
+
if (_stateBorrowed > BigInt(0))
|
|
709
|
+
return "0.0";
|
|
710
|
+
if (!(yield this.leverageRepayIsAvailable(stateCollateral, userCollateral, userBorrowed, address)))
|
|
711
|
+
return "0.0";
|
|
712
|
+
const { _totalBorrowed } = this._leverageRepayExpectedBorrowed(stateCollateral, userCollateral, userBorrowed);
|
|
713
|
+
const _dCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]) * BigInt(-1);
|
|
714
|
+
const _dDebt = _totalBorrowed * BigInt(-1);
|
|
715
|
+
if (_debt + _dDebt <= BigInt(0))
|
|
716
|
+
return "0.0";
|
|
717
|
+
const contract = this.llamalend.contracts[this.market.controller].contract;
|
|
718
|
+
let _health = yield contract.health_calculator(address, _dCollateral, _dDebt, full, _N, this.llamalend.constantOptions);
|
|
719
|
+
_health = _health * BigInt(100);
|
|
720
|
+
return this.llamalend.formatUnits(_health);
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
leverageRepayIsApproved(userCollateral, userBorrowed) {
|
|
724
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
725
|
+
this._checkLeverageZap();
|
|
726
|
+
return yield hasAllowance.call(this.llamalend, [this.market.coinAddresses[1], this.market.coinAddresses[0]], [userCollateral, userBorrowed], this.llamalend.signerAddress, this.llamalend.constants.ALIASES.leverage_zap);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
leverageRepayApproveEstimateGas(userCollateral, userBorrowed) {
|
|
730
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
731
|
+
this._checkLeverageZap();
|
|
732
|
+
return yield ensureAllowanceEstimateGas.call(this.llamalend, [this.market.coinAddresses[1], this.market.coinAddresses[0]], [userCollateral, userBorrowed], this.llamalend.constants.ALIASES.leverage_zap);
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
leverageRepayApprove(userCollateral, userBorrowed) {
|
|
736
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
737
|
+
this._checkLeverageZap();
|
|
738
|
+
return yield ensureAllowance.call(this.llamalend, [this.market.coinAddresses[1], this.market.coinAddresses[0]], [userCollateral, userBorrowed], this.llamalend.constants.ALIASES.leverage_zap);
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
leverageRepayRouteImage(stateCollateral, userCollateral) {
|
|
742
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
743
|
+
this._checkLeverageZap();
|
|
744
|
+
const _stateCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]);
|
|
745
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
746
|
+
return this._getSwapDataFromCache(this.market.coinAddresses[1], _stateCollateral + _userCollateral).pathVizImage;
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
_leverageRepay(stateCollateral, userCollateral, userBorrowed, slippage, estimateGas) {
|
|
750
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
751
|
+
if (!(yield this.userLoanExists()))
|
|
752
|
+
throw Error("Loan does not exist");
|
|
753
|
+
const _stateCollateral = parseUnits(stateCollateral, this.market.coinDecimals[1]);
|
|
754
|
+
const _userCollateral = parseUnits(userCollateral, this.market.coinDecimals[1]);
|
|
755
|
+
const _userBorrowed = parseUnits(userBorrowed, this.market.coinDecimals[0]);
|
|
756
|
+
let calldata = "0x";
|
|
757
|
+
if (_stateCollateral + _userCollateral > BigInt(0)) {
|
|
758
|
+
const swapData = this._getSwapDataFromCache(this.market.coinAddresses[1], _stateCollateral + _userCollateral);
|
|
759
|
+
if (slippage !== swapData.slippage)
|
|
760
|
+
throw Error(`You must call leverage.repayExpectedBorrowed() with slippage=${slippage} first`);
|
|
761
|
+
calldata = yield _assembleTxOdos.call(this.llamalend, swapData.pathId);
|
|
762
|
+
}
|
|
763
|
+
console.log('params', [1, parseUnits(this._getMarketId(), 0), _userCollateral, _userBorrowed], calldata);
|
|
764
|
+
const contract = this.llamalend.contracts[this.market.controller].contract;
|
|
765
|
+
const gas = yield contract.repay_extended.estimateGas(this.llamalend.constants.ALIASES.leverage_zap, [1, parseUnits(this._getMarketId(), 0), _userCollateral, _userBorrowed], calldata);
|
|
766
|
+
if (estimateGas)
|
|
767
|
+
return smartNumber(gas);
|
|
768
|
+
yield this.llamalend.updateFeeData();
|
|
769
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
770
|
+
return (yield contract.repay_extended(this.llamalend.constants.ALIASES.leverage_zap, [1, parseUnits(this._getMarketId(), 0), _userCollateral, _userBorrowed], calldata, Object.assign(Object.assign({}, this.llamalend.options), { gasLimit }))).hash;
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
leverageRepayEstimateGas(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
774
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, slippage = 0.1) {
|
|
775
|
+
this._checkLeverageZap();
|
|
776
|
+
if (!(yield this.leverageRepayIsApproved(userCollateral, userBorrowed)))
|
|
777
|
+
throw Error("Approval is needed for gas estimation");
|
|
778
|
+
return yield this._leverageRepay(stateCollateral, userCollateral, userBorrowed, slippage, true);
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
leverageRepay(stateCollateral_1, userCollateral_1, userBorrowed_1) {
|
|
782
|
+
return __awaiter(this, arguments, void 0, function* (stateCollateral, userCollateral, userBorrowed, slippage = 0.1) {
|
|
783
|
+
this._checkLeverageZap();
|
|
784
|
+
yield this.leverageRepayApprove(userCollateral, userBorrowed);
|
|
785
|
+
return yield this._leverageRepay(stateCollateral, userCollateral, userBorrowed, slippage, false);
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
}
|