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