@curvefi/llamalend-api 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +40 -0
- package/.github/workflows/lint.yml +15 -0
- package/.github/workflows/publish.yml +55 -0
- package/LICENSE +21 -0
- package/README.md +1976 -0
- package/lib/cache/index.d.ts +14 -0
- package/lib/cache/index.js +31 -0
- package/lib/constants/L2Networks.d.ts +1 -0
- package/lib/constants/L2Networks.js +1 -0
- package/lib/constants/abis/Controller.json +1027 -0
- package/lib/constants/abis/ERC20.json +222 -0
- package/lib/constants/abis/ERC4626.json +1674 -0
- package/lib/constants/abis/GaugeController.json +794 -0
- package/lib/constants/abis/GaugeFactoryMainnet.json +1 -0
- package/lib/constants/abis/GaugeFactorySidechain.json +475 -0
- package/lib/constants/abis/GaugeV5.json +958 -0
- package/lib/constants/abis/LeverageZap.json +35 -0
- package/lib/constants/abis/Llamma.json +984 -0
- package/lib/constants/abis/Minter.json +1 -0
- package/lib/constants/abis/MonetaryPolicy.json +221 -0
- package/lib/constants/abis/OneWayLendingFactoryABI.json +899 -0
- package/lib/constants/abis/SidechainGauge.json +939 -0
- package/lib/constants/abis/Vault.json +721 -0
- package/lib/constants/abis/crvUSD/DeleverageZap.json +248 -0
- package/lib/constants/abis/crvUSD/Factory.json +514 -0
- package/lib/constants/abis/crvUSD/HealthCalculatorZap.json +54 -0
- package/lib/constants/abis/crvUSD/LeverageZap.json +312 -0
- package/lib/constants/abis/crvUSD/MonetaryPolicy.json +294 -0
- package/lib/constants/abis/crvUSD/MonetaryPolicy2.json +299 -0
- package/lib/constants/abis/crvUSD/PegKeeper.json +411 -0
- package/lib/constants/abis/crvUSD/controller.json +991 -0
- package/lib/constants/abis/crvUSD/llamma.json +984 -0
- package/lib/constants/abis/gas_oracle_optimism.json +149 -0
- package/lib/constants/abis/gas_oracle_optimism_blob.json +203 -0
- package/lib/constants/aliases.d.ts +16 -0
- package/lib/constants/aliases.js +124 -0
- package/lib/constants/coins.d.ts +16 -0
- package/lib/constants/coins.js +24 -0
- package/lib/constants/llammas.d.ts +2 -0
- package/lib/constants/llammas.js +96 -0
- package/lib/constants/utils.d.ts +4 -0
- package/lib/constants/utils.js +27 -0
- package/lib/external-api.d.ts +13 -0
- package/lib/external-api.js +436 -0
- package/lib/index.d.ts +104 -0
- package/lib/index.js +123 -0
- package/lib/interfaces.d.ts +228 -0
- package/lib/interfaces.js +1 -0
- package/lib/lendMarkets/LendMarketTemplate.d.ts +510 -0
- package/lib/lendMarkets/LendMarketTemplate.js +4682 -0
- package/lib/lendMarkets/index.d.ts +3 -0
- package/lib/lendMarkets/index.js +3 -0
- package/lib/lendMarkets/lendMarketConstructor.d.ts +2 -0
- package/lib/lendMarkets/lendMarketConstructor.js +6 -0
- package/lib/llamalend.d.ts +80 -0
- package/lib/llamalend.js +878 -0
- package/lib/mintMarkets/MintMarketTemplate.d.ts +308 -0
- package/lib/mintMarkets/MintMarketTemplate.js +2998 -0
- package/lib/mintMarkets/index.d.ts +3 -0
- package/lib/mintMarkets/index.js +3 -0
- package/lib/mintMarkets/mintMarketConstructor.d.ts +2 -0
- package/lib/mintMarkets/mintMarketConstructor.js +4 -0
- package/lib/st-crvUSD.d.ts +35 -0
- package/lib/st-crvUSD.js +505 -0
- package/lib/utils.d.ts +58 -0
- package/lib/utils.js +661 -0
- package/package.json +42 -0
- package/src/cache/index.ts +41 -0
- package/src/constants/L2Networks.ts +1 -0
- package/src/constants/abis/Controller.json +1027 -0
- package/src/constants/abis/ERC20.json +222 -0
- package/src/constants/abis/ERC4626.json +1674 -0
- package/src/constants/abis/GaugeController.json +794 -0
- package/src/constants/abis/GaugeFactoryMainnet.json +1 -0
- package/src/constants/abis/GaugeFactorySidechain.json +475 -0
- package/src/constants/abis/GaugeV5.json +958 -0
- package/src/constants/abis/LeverageZap.json +35 -0
- package/src/constants/abis/Llamma.json +984 -0
- package/src/constants/abis/Minter.json +1 -0
- package/src/constants/abis/MonetaryPolicy.json +221 -0
- package/src/constants/abis/OneWayLendingFactoryABI.json +899 -0
- package/src/constants/abis/SidechainGauge.json +939 -0
- package/src/constants/abis/Vault.json +721 -0
- package/src/constants/abis/crvUSD/DeleverageZap.json +248 -0
- package/src/constants/abis/crvUSD/ERC20.json +222 -0
- package/src/constants/abis/crvUSD/Factory.json +514 -0
- package/src/constants/abis/crvUSD/HealthCalculatorZap.json +54 -0
- package/src/constants/abis/crvUSD/LeverageZap.json +312 -0
- package/src/constants/abis/crvUSD/MonetaryPolicy.json +294 -0
- package/src/constants/abis/crvUSD/MonetaryPolicy2.json +299 -0
- package/src/constants/abis/crvUSD/PegKeeper.json +411 -0
- package/src/constants/abis/crvUSD/controller.json +991 -0
- package/src/constants/abis/crvUSD/llamma.json +984 -0
- package/src/constants/abis/gas_oracle_optimism.json +149 -0
- package/src/constants/abis/gas_oracle_optimism_blob.json +203 -0
- package/src/constants/aliases.ts +141 -0
- package/src/constants/coins.ts +41 -0
- package/src/constants/llammas.ts +99 -0
- package/src/constants/utils.ts +33 -0
- package/src/external-api.ts +325 -0
- package/src/index.ts +128 -0
- package/src/interfaces.ts +237 -0
- package/src/lendMarkets/LendMarketTemplate.ts +3022 -0
- package/src/lendMarkets/index.ts +7 -0
- package/src/lendMarkets/lendMarketConstructor.ts +7 -0
- package/src/llamalend.ts +785 -0
- package/src/mintMarkets/MintMarketTemplate.ts +1781 -0
- package/src/mintMarkets/index.ts +7 -0
- package/src/mintMarkets/mintMarketConstructor.ts +5 -0
- package/src/st-crvUSD.ts +244 -0
- package/src/utils.ts +497 -0
- package/test/fetch.test.ts +152 -0
- package/test/general.test.ts +216 -0
- package/test/leverageBorrowMore.test.ts +245 -0
- package/test/leverageCreateLoan.test.ts +236 -0
- package/test/leverageRepay.test.ts +240 -0
- package/test/readme.test.ts +475 -0
- package/test/selfLiquidate.test.ts +57 -0
- package/test/selfLiquidateCrvUSD.test.ts +54 -0
- package/test/st_crvUSD.test.ts +68 -0
- package/test/swap.test.ts +62 -0
- package/test/swapCrvUSD.test.ts +56 -0
- package/test/vault.test.ts +112 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +72 -0
|
@@ -0,0 +1,1781 @@
|
|
|
1
|
+
import memoize from "memoizee";
|
|
2
|
+
import BigNumber from "bignumber.js";
|
|
3
|
+
import { llamalend } from "../llamalend.js";
|
|
4
|
+
import {
|
|
5
|
+
_getAddress,
|
|
6
|
+
parseUnits,
|
|
7
|
+
BN,
|
|
8
|
+
toBN,
|
|
9
|
+
fromBN,
|
|
10
|
+
getBalances,
|
|
11
|
+
ensureAllowance,
|
|
12
|
+
hasAllowance,
|
|
13
|
+
ensureAllowanceEstimateGas,
|
|
14
|
+
isEth,
|
|
15
|
+
_cutZeros,
|
|
16
|
+
formatUnits,
|
|
17
|
+
smartNumber,
|
|
18
|
+
MAX_ALLOWANCE,
|
|
19
|
+
MAX_ACTIVE_BAND, _mulBy1_3, DIGas,
|
|
20
|
+
} from "../utils";
|
|
21
|
+
import {IDict, TGas} from "../interfaces";
|
|
22
|
+
import {_getUserCollateralCrvUsd} from "../external-api.js";
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export class MintMarketTemplate {
|
|
26
|
+
id: string;
|
|
27
|
+
address: string;
|
|
28
|
+
controller: string;
|
|
29
|
+
monetaryPolicy: string;
|
|
30
|
+
collateral: string;
|
|
31
|
+
leverageZap: string;
|
|
32
|
+
deleverageZap: string;
|
|
33
|
+
healthCalculator: string | undefined;
|
|
34
|
+
collateralSymbol: string;
|
|
35
|
+
collateralDecimals: number;
|
|
36
|
+
coins: string[];
|
|
37
|
+
coinAddresses: string[];
|
|
38
|
+
coinDecimals: number[];
|
|
39
|
+
minBands: number;
|
|
40
|
+
maxBands: number;
|
|
41
|
+
defaultBands: number;
|
|
42
|
+
A: number;
|
|
43
|
+
tickSpace: number; // %
|
|
44
|
+
estimateGas: {
|
|
45
|
+
createLoanApprove: (collateral: number | string) => Promise<TGas>,
|
|
46
|
+
createLoan: (collateral: number | string, debt: number | string, range: number) => Promise<TGas>,
|
|
47
|
+
addCollateralApprove: (collateral: number | string) => Promise<TGas>,
|
|
48
|
+
addCollateral: (collateral: number | string, address?: string) => Promise<TGas>,
|
|
49
|
+
borrowMoreApprove: (collateral: number | string) => Promise<TGas>,
|
|
50
|
+
borrowMore: (collateral: number | string, debt: number | string) => Promise<TGas>,
|
|
51
|
+
repayApprove: (debt: number | string) => Promise<TGas>,
|
|
52
|
+
repay: (debt: number | string, address?: string) => Promise<TGas>,
|
|
53
|
+
fullRepayApprove: (address?: string) => Promise<TGas>,
|
|
54
|
+
fullRepay: (address?: string) => Promise<TGas>,
|
|
55
|
+
swapApprove: (i: number, amount: number | string) => Promise<TGas>,
|
|
56
|
+
swap: (i: number, j: number, amount: number | string, slippage?: number) => Promise<TGas>,
|
|
57
|
+
liquidateApprove: (address: string) => Promise<TGas>,
|
|
58
|
+
liquidate: (address: string, slippage?: number) => Promise<TGas>,
|
|
59
|
+
selfLiquidateApprove: () => Promise<TGas>,
|
|
60
|
+
selfLiquidate: (slippage?: number) => Promise<TGas>,
|
|
61
|
+
};
|
|
62
|
+
stats: {
|
|
63
|
+
parameters: () => Promise<{
|
|
64
|
+
fee: string, // %
|
|
65
|
+
admin_fee: string, // %
|
|
66
|
+
rate: string, // %
|
|
67
|
+
liquidation_discount: string, // %
|
|
68
|
+
loan_discount: string, // %
|
|
69
|
+
}>,
|
|
70
|
+
balances: () => Promise<[string, string]>,
|
|
71
|
+
maxMinBands: () => Promise<[number, number]>,
|
|
72
|
+
activeBand:() => Promise<number>,
|
|
73
|
+
liquidatingBand:() => Promise<number | null>,
|
|
74
|
+
bandBalances:(n: number) => Promise<{ stablecoin: string, collateral: string }>,
|
|
75
|
+
bandsBalances: () => Promise<{ [index: number]: { stablecoin: string, collateral: string } }>,
|
|
76
|
+
totalSupply: () => Promise<string>,
|
|
77
|
+
totalDebt: () => Promise<string>,
|
|
78
|
+
totalStablecoin: () => Promise<string>,
|
|
79
|
+
totalCollateral: () => Promise<string>,
|
|
80
|
+
capAndAvailable: () => Promise<{ "cap": string, "available": string }>,
|
|
81
|
+
};
|
|
82
|
+
wallet: {
|
|
83
|
+
balances: (address?: string) => Promise<{ stablecoin: string, collateral: string }>,
|
|
84
|
+
};
|
|
85
|
+
leverage: {
|
|
86
|
+
createLoanMaxRecv: (collateral: number | string, range: number) => Promise<{ maxBorrowable: string, maxCollateral: string, leverage: string, routeIdx: number }>,
|
|
87
|
+
createLoanMaxRecvAllRanges: (collateral: number | string) => Promise<IDict<{ maxBorrowable: string, maxCollateral: string, leverage: string, routeIdx: number }>>,
|
|
88
|
+
createLoanCollateral: (userCollateral: number | string, debt: number | string) => Promise<{ collateral: string, leverage: string, routeIdx: number }>,
|
|
89
|
+
getRouteName: (routeIdx: number) => Promise<string>,
|
|
90
|
+
getMaxRange: (collateral: number | string, debt: number | string) => Promise<number>,
|
|
91
|
+
createLoanBands: (collateral: number | string, debt: number | string, range: number) => Promise<[number, number]>,
|
|
92
|
+
createLoanBandsAllRanges: (collateral: number | string, debt: number | string) => Promise<IDict<[number, number] | null>>,
|
|
93
|
+
createLoanPrices: (collateral: number | string, debt: number | string, range: number) => Promise<string[]>,
|
|
94
|
+
createLoanPricesAllRanges: (collateral: number | string, debt: number | string) => Promise<IDict<[string, string] | null>>,
|
|
95
|
+
createLoanHealth: (collateral: number | string, debt: number | string, range: number, full?: boolean, address?: string) => Promise<string>,
|
|
96
|
+
createLoanIsApproved: (collateral: number | string) => Promise<boolean>,
|
|
97
|
+
createLoanApprove: (collateral: number | string) => Promise<string[]>,
|
|
98
|
+
priceImpact: (collateral: number | string, debt: number | string) => Promise<string>,
|
|
99
|
+
createLoan: (collateral: number | string, debt: number | string, range: number, slippage?: number) => Promise<string>,
|
|
100
|
+
estimateGas: {
|
|
101
|
+
createLoanApprove: (collateral: number | string) => Promise<TGas>,
|
|
102
|
+
createLoan: (collateral: number | string, debt: number | string, range: number, slippage?: number) => Promise<TGas>,
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
deleverage: {
|
|
106
|
+
repayStablecoins: (collateral: number | string) => Promise<{ stablecoins: string, routeIdx: number }>,
|
|
107
|
+
getRouteName: (routeIdx: number) => Promise<string>,
|
|
108
|
+
isAvailable: (deleverageCollateral: number | string, address?: string) => Promise<boolean>,
|
|
109
|
+
isFullRepayment: (deleverageCollateral: number | string, address?: string) => Promise<boolean>,
|
|
110
|
+
repayBands: (collateral: number | string, address?: string) => Promise<[number, number]>,
|
|
111
|
+
repayPrices: (collateral: number | string, address?: string) => Promise<string[]>,
|
|
112
|
+
repayHealth: (collateral: number | string, full?: boolean, address?: string) => Promise<string>,
|
|
113
|
+
repay: (collateral: number | string, slippage?: number) => Promise<string>,
|
|
114
|
+
priceImpact: (collateral: number | string) => Promise<string>,
|
|
115
|
+
estimateGas: {
|
|
116
|
+
repay: (collateral: number | string, slippage?: number) => Promise<number>,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
constructor(id: string) {
|
|
121
|
+
const llammaData = llamalend.constants.LLAMMAS[id];
|
|
122
|
+
|
|
123
|
+
this.id = id;
|
|
124
|
+
this.address = llammaData.amm_address;
|
|
125
|
+
this.controller = llammaData.controller_address;
|
|
126
|
+
this.monetaryPolicy = llammaData.monetary_policy_address;
|
|
127
|
+
this.collateral = llammaData.collateral_address;
|
|
128
|
+
this.leverageZap = llammaData.leverage_zap;
|
|
129
|
+
this.deleverageZap = llammaData.deleverage_zap;
|
|
130
|
+
this.healthCalculator = llammaData.health_calculator_zap;
|
|
131
|
+
this.collateralSymbol = llammaData.collateral_symbol;
|
|
132
|
+
this.collateralDecimals = llammaData.collateral_decimals;
|
|
133
|
+
this.coins = ["crvUSD", llammaData.collateral_symbol];
|
|
134
|
+
this.coinAddresses = [llamalend.address, llammaData.collateral_address];
|
|
135
|
+
this.coinDecimals = [18, llammaData.collateral_decimals];
|
|
136
|
+
this.minBands = llammaData.min_bands;
|
|
137
|
+
this.maxBands = llammaData.max_bands;
|
|
138
|
+
this.defaultBands = llammaData.default_bands;
|
|
139
|
+
this.A = llammaData.A;
|
|
140
|
+
this.tickSpace = 1 / llammaData.A * 100;
|
|
141
|
+
this.estimateGas = {
|
|
142
|
+
createLoanApprove: this.createLoanApproveEstimateGas.bind(this),
|
|
143
|
+
createLoan: this.createLoanEstimateGas.bind(this),
|
|
144
|
+
addCollateralApprove: this.addCollateralApproveEstimateGas.bind(this),
|
|
145
|
+
addCollateral: this.addCollateralEstimateGas.bind(this),
|
|
146
|
+
borrowMoreApprove: this.borrowMoreApproveEstimateGas.bind(this),
|
|
147
|
+
borrowMore: this.borrowMoreEstimateGas.bind(this),
|
|
148
|
+
repayApprove: this.repayApproveEstimateGas.bind(this),
|
|
149
|
+
repay: this.repayEstimateGas.bind(this),
|
|
150
|
+
fullRepayApprove: this.fullRepayApproveEstimateGas.bind(this),
|
|
151
|
+
fullRepay: this.fullRepayEstimateGas.bind(this),
|
|
152
|
+
swapApprove: this.swapApproveEstimateGas.bind(this),
|
|
153
|
+
swap: this.swapEstimateGas.bind(this),
|
|
154
|
+
liquidateApprove: this.liquidateApproveEstimateGas.bind(this),
|
|
155
|
+
liquidate: this.liquidateEstimateGas.bind(this),
|
|
156
|
+
selfLiquidateApprove: this.selfLiquidateApproveEstimateGas.bind(this),
|
|
157
|
+
selfLiquidate: this.selfLiquidateEstimateGas.bind(this),
|
|
158
|
+
}
|
|
159
|
+
this.stats = {
|
|
160
|
+
parameters: this.statsParameters.bind(this),
|
|
161
|
+
balances: this.statsBalances.bind(this),
|
|
162
|
+
maxMinBands: this.statsMaxMinBands.bind(this),
|
|
163
|
+
activeBand: this.statsActiveBand.bind(this),
|
|
164
|
+
liquidatingBand: this.statsLiquidatingBand.bind(this),
|
|
165
|
+
bandBalances: this.statsBandBalances.bind(this),
|
|
166
|
+
bandsBalances: this.statsBandsBalances.bind(this),
|
|
167
|
+
totalSupply: this.statsTotalSupply.bind(this),
|
|
168
|
+
totalDebt: this.statsTotalDebt.bind(this),
|
|
169
|
+
totalStablecoin: this.statsTotalStablecoin.bind(this),
|
|
170
|
+
totalCollateral: this.statsTotalCollateral.bind(this),
|
|
171
|
+
capAndAvailable: this.statsCapAndAvailable.bind(this),
|
|
172
|
+
}
|
|
173
|
+
this.wallet = {
|
|
174
|
+
balances: this.walletBalances.bind(this),
|
|
175
|
+
}
|
|
176
|
+
this.leverage = {
|
|
177
|
+
createLoanMaxRecv: this.leverageCreateLoanMaxRecv.bind(this),
|
|
178
|
+
createLoanMaxRecvAllRanges: this.leverageCreateLoanMaxRecvAllRanges.bind(this),
|
|
179
|
+
createLoanCollateral: this.leverageCreateLoanCollateral.bind(this),
|
|
180
|
+
getRouteName: this.leverageGetRouteName.bind(this),
|
|
181
|
+
getMaxRange: this.leverageGetMaxRange.bind(this),
|
|
182
|
+
createLoanBands: this.leverageCreateLoanBands.bind(this),
|
|
183
|
+
createLoanBandsAllRanges: this.leverageCreateLoanBandsAllRanges.bind(this),
|
|
184
|
+
createLoanPrices: this.leverageCreateLoanPrices.bind(this),
|
|
185
|
+
createLoanPricesAllRanges: this.leverageCreateLoanPricesAllRanges.bind(this),
|
|
186
|
+
createLoanHealth: this.leverageCreateLoanHealth.bind(this),
|
|
187
|
+
createLoanIsApproved: this.createLoanIsApproved.bind(this),
|
|
188
|
+
createLoanApprove: this.createLoanApprove.bind(this),
|
|
189
|
+
priceImpact: this.leveragePriceImpact.bind(this),
|
|
190
|
+
createLoan: this.leverageCreateLoan.bind(this),
|
|
191
|
+
estimateGas: {
|
|
192
|
+
createLoanApprove: this.createLoanApproveEstimateGas.bind(this),
|
|
193
|
+
createLoan: this.leverageCreateLoanEstimateGas.bind(this),
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
this.deleverage = {
|
|
197
|
+
repayStablecoins: this.deleverageRepayStablecoins.bind(this),
|
|
198
|
+
getRouteName: this.deleverageGetRouteName.bind(this),
|
|
199
|
+
isAvailable: this.deleverageIsAvailable.bind(this),
|
|
200
|
+
isFullRepayment: this.deleverageIsFullRepayment.bind(this),
|
|
201
|
+
repayBands: this.deleverageRepayBands.bind(this),
|
|
202
|
+
repayPrices: this.deleverageRepayPrices.bind(this),
|
|
203
|
+
repayHealth: this.deleverageRepayHealth.bind(this),
|
|
204
|
+
priceImpact: this.deleveragePriceImpact.bind(this),
|
|
205
|
+
repay: this.deleverageRepay.bind(this),
|
|
206
|
+
estimateGas: {
|
|
207
|
+
repay: this.deleverageRepayEstimateGas.bind(this),
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ---------------- STATS ----------------
|
|
213
|
+
|
|
214
|
+
private statsParameters = memoize(async (): Promise<{
|
|
215
|
+
fee: string, // %
|
|
216
|
+
admin_fee: string, // %
|
|
217
|
+
rate: string, // %
|
|
218
|
+
future_rate: string, // %
|
|
219
|
+
liquidation_discount: string, // %
|
|
220
|
+
loan_discount: string, // %
|
|
221
|
+
}> => {
|
|
222
|
+
const llammaContract = llamalend.contracts[this.address].multicallContract;
|
|
223
|
+
const controllerContract = llamalend.contracts[this.controller].multicallContract;
|
|
224
|
+
const monetaryPolicyContract = llamalend.contracts[this.monetaryPolicy].multicallContract;
|
|
225
|
+
|
|
226
|
+
const calls = [
|
|
227
|
+
llammaContract.fee(),
|
|
228
|
+
llammaContract.admin_fee(),
|
|
229
|
+
llammaContract.rate(),
|
|
230
|
+
"rate(address)" in llamalend.contracts[this.monetaryPolicy].contract ? monetaryPolicyContract.rate(this.controller) : monetaryPolicyContract.rate(),
|
|
231
|
+
controllerContract.liquidation_discount(),
|
|
232
|
+
controllerContract.loan_discount(),
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
const [_fee, _admin_fee, _rate, _mp_rate, _liquidation_discount, _loan_discount]: bigint[] = await llamalend.multicallProvider.all(calls) as bigint[];
|
|
236
|
+
const [fee, admin_fee, liquidation_discount, loan_discount] = [_fee, _admin_fee, _liquidation_discount, _loan_discount]
|
|
237
|
+
.map((x) => formatUnits(x * BigInt(100)));
|
|
238
|
+
|
|
239
|
+
// (1+rate)**(365*86400)-1 ~= (e**(rate*365*86400))-1
|
|
240
|
+
const rate = String(((2.718281828459 ** (toBN(_rate).times(365).times(86400)).toNumber()) - 1) * 100);
|
|
241
|
+
const future_rate = String(((2.718281828459 ** (toBN(_mp_rate).times(365).times(86400)).toNumber()) - 1) * 100);
|
|
242
|
+
|
|
243
|
+
return { fee, admin_fee, rate, future_rate, liquidation_discount, loan_discount }
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
promise: true,
|
|
247
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
private async statsBalances(): Promise<[string, string]> {
|
|
251
|
+
const crvusdContract = llamalend.contracts[llamalend.address].multicallContract;
|
|
252
|
+
const collateralContract = llamalend.contracts[isEth(this.collateral) ? llamalend.constants.WETH : this.collateral].multicallContract;
|
|
253
|
+
const contract = llamalend.contracts[this.address].multicallContract;
|
|
254
|
+
const calls = [
|
|
255
|
+
crvusdContract.balanceOf(this.address),
|
|
256
|
+
collateralContract.balanceOf(this.address),
|
|
257
|
+
contract.admin_fees_x(),
|
|
258
|
+
contract.admin_fees_y(),
|
|
259
|
+
]
|
|
260
|
+
const [_crvusdBalance, _collateralBalance, _crvusdAdminFees, _collateralAdminFees]: bigint[] = await llamalend.multicallProvider.all(calls);
|
|
261
|
+
|
|
262
|
+
return [
|
|
263
|
+
formatUnits(_crvusdBalance - _crvusdAdminFees),
|
|
264
|
+
formatUnits(_collateralBalance - _collateralAdminFees, this.collateralDecimals),
|
|
265
|
+
];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private statsMaxMinBands = memoize(async (): Promise<[number, number]> => {
|
|
269
|
+
const llammaContract = llamalend.contracts[this.address].multicallContract;
|
|
270
|
+
|
|
271
|
+
const calls1 = [
|
|
272
|
+
llammaContract.max_band(),
|
|
273
|
+
llammaContract.min_band(),
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
return (await llamalend.multicallProvider.all(calls1) as BigNumber[]).map((_b) => _b.toNumber()) as [number, number];
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
promise: true,
|
|
280
|
+
maxAge: 60 * 1000, // 1m
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
private statsActiveBand = memoize(async (): Promise<number> => {
|
|
284
|
+
return (await llamalend.contracts[this.address].contract.active_band()).toNumber()
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
promise: true,
|
|
288
|
+
maxAge: 60 * 1000, // 1m
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
private async statsLiquidatingBand(): Promise<number | null> {
|
|
292
|
+
const activeBand = await this.statsActiveBand();
|
|
293
|
+
const { stablecoin, collateral } = await this.statsBandBalances(activeBand);
|
|
294
|
+
if (Number(stablecoin) > 0 && Number(collateral) > 0) return activeBand;
|
|
295
|
+
return null
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private async statsBandBalances(n: number): Promise<{ stablecoin: string, collateral: string }> {
|
|
299
|
+
const llammaContract = llamalend.contracts[this.address].multicallContract;
|
|
300
|
+
const calls = [];
|
|
301
|
+
calls.push(llammaContract.bands_x(n), llammaContract.bands_y(n));
|
|
302
|
+
|
|
303
|
+
const _balances: bigint[] = await llamalend.multicallProvider.all(calls);
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
stablecoin: formatUnits(_balances[0]),
|
|
307
|
+
collateral: formatUnits(_balances[1], this.collateralDecimals),
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private async statsBandsBalances(): Promise<{ [index: number]: { stablecoin: string, collateral: string } }> {
|
|
312
|
+
const [max_band, min_band]: number[] = await this.statsMaxMinBands();
|
|
313
|
+
|
|
314
|
+
const llammaContract = llamalend.contracts[this.address].multicallContract;
|
|
315
|
+
const calls = [];
|
|
316
|
+
for (let i = min_band; i <= max_band; i++) {
|
|
317
|
+
calls.push(llammaContract.bands_x(i), llammaContract.bands_y(i));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const _bands: bigint[] = await llamalend.multicallProvider.all(calls);
|
|
321
|
+
|
|
322
|
+
const bands: { [index: number]: { stablecoin: string, collateral: string } } = {};
|
|
323
|
+
for (let i = min_band; i <= max_band; i++) {
|
|
324
|
+
const _i = i - min_band
|
|
325
|
+
let collateral = formatUnits(_bands[(2 * _i) + 1]);
|
|
326
|
+
collateral = collateral.split(".")[0] + "." +
|
|
327
|
+
(collateral.split(".")[1] || "0").slice(0, this.collateralDecimals);
|
|
328
|
+
bands[i] = {
|
|
329
|
+
stablecoin: formatUnits(_bands[2 * _i]),
|
|
330
|
+
collateral,
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return bands
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private statsTotalSupply = memoize(async (): Promise<string> => {
|
|
338
|
+
const controllerContract = llamalend.contracts[this.controller].multicallContract;
|
|
339
|
+
const calls = [controllerContract.minted(), controllerContract.redeemed()]
|
|
340
|
+
const [_minted, _redeemed]: bigint[] = await llamalend.multicallProvider.all(calls);
|
|
341
|
+
|
|
342
|
+
return toBN(_minted).minus(toBN(_redeemed)).toString();
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
promise: true,
|
|
346
|
+
maxAge: 60 * 1000, // 1m
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
private statsTotalDebt = memoize(async (): Promise<string> => {
|
|
350
|
+
const debt = await llamalend.contracts[this.controller].contract.total_debt(llamalend.constantOptions);
|
|
351
|
+
|
|
352
|
+
return formatUnits(debt);
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
promise: true,
|
|
356
|
+
maxAge: 60 * 1000, // 1m
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
private statsTotalStablecoin = memoize(async (): Promise<string> => {
|
|
360
|
+
const stablecoinContract = llamalend.contracts[llamalend.address].multicallContract;
|
|
361
|
+
const ammContract = llamalend.contracts[this.address].multicallContract;
|
|
362
|
+
|
|
363
|
+
const [_balance, _fee]: bigint[] = await llamalend.multicallProvider.all([
|
|
364
|
+
stablecoinContract.balanceOf(this.address),
|
|
365
|
+
ammContract.admin_fees_x(),
|
|
366
|
+
]);
|
|
367
|
+
|
|
368
|
+
return toBN(_balance).minus(toBN(_fee)).toString()
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
promise: true,
|
|
372
|
+
maxAge: 60 * 1000, // 1m
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
private statsTotalCollateral = memoize(async (): Promise<string> => {
|
|
376
|
+
const collateralContract = llamalend.contracts[isEth(this.collateral) ? llamalend.constants.WETH : this.collateral].multicallContract;
|
|
377
|
+
const ammContract = llamalend.contracts[this.address].multicallContract;
|
|
378
|
+
|
|
379
|
+
const [_balance, _fee]: bigint[] = await llamalend.multicallProvider.all([
|
|
380
|
+
collateralContract.balanceOf(this.address),
|
|
381
|
+
ammContract.admin_fees_y(),
|
|
382
|
+
]);
|
|
383
|
+
|
|
384
|
+
return toBN(_balance, this.collateralDecimals).minus(toBN(_fee, this.collateralDecimals)).toString()
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
promise: true,
|
|
388
|
+
maxAge: 60 * 1000, // 1m
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
private statsCapAndAvailable = memoize(async (): Promise<{ "cap": string, "available": string }> => {
|
|
392
|
+
const factoryContract = llamalend.contracts[llamalend.constants.FACTORY].multicallContract;
|
|
393
|
+
const crvusdContract = llamalend.contracts[llamalend.address].multicallContract;
|
|
394
|
+
|
|
395
|
+
const [_cap, _available]: bigint[] = await llamalend.multicallProvider.all([
|
|
396
|
+
factoryContract.debt_ceiling(this.controller),
|
|
397
|
+
crvusdContract.balanceOf(this.controller),
|
|
398
|
+
]);
|
|
399
|
+
|
|
400
|
+
return { "cap": llamalend.formatUnits(_cap), "available": llamalend.formatUnits(_available) }
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
promise: true,
|
|
404
|
+
maxAge: 60 * 1000, // 1m
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// ---------------------------------------
|
|
408
|
+
|
|
409
|
+
public async loanExists(address = ""): Promise<boolean> {
|
|
410
|
+
address = _getAddress(address);
|
|
411
|
+
return await llamalend.contracts[this.controller].contract.loan_exists(address, llamalend.constantOptions);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
public async userDebt(address = ""): Promise<string> {
|
|
415
|
+
address = _getAddress(address);
|
|
416
|
+
const debt = await llamalend.contracts[this.controller].contract.debt(address, llamalend.constantOptions);
|
|
417
|
+
|
|
418
|
+
return formatUnits(debt);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
public async userHealth(full = true, address = ""): Promise<string> {
|
|
422
|
+
address = _getAddress(address);
|
|
423
|
+
let _health = await llamalend.contracts[this.controller].contract.health(address, full, llamalend.constantOptions) as bigint;
|
|
424
|
+
_health = _health * BigInt(100);
|
|
425
|
+
|
|
426
|
+
return formatUnits(_health);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
public async userBands(address = ""): Promise<number[]> {
|
|
430
|
+
address = _getAddress(address);
|
|
431
|
+
const _bands = await llamalend.contracts[this.address].contract.read_user_tick_numbers(address, llamalend.constantOptions) as BigNumber[];
|
|
432
|
+
|
|
433
|
+
return _bands.map((_t) => _t.toNumber()).reverse();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
public async userRange(address = ""): Promise<number> {
|
|
437
|
+
const [n2, n1] = await this.userBands(address);
|
|
438
|
+
if (n1 == n2) return 0;
|
|
439
|
+
return n2 - n1 + 1;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
public async userPrices(address = ""): Promise<string[]> {
|
|
443
|
+
address = _getAddress(address);
|
|
444
|
+
const _prices = await llamalend.contracts[this.controller].contract.user_prices(address, llamalend.constantOptions) as bigint[];
|
|
445
|
+
|
|
446
|
+
return _prices.map((_p) =>formatUnits(_p)).reverse();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
public async _userState(address = ""): Promise<{ _collateral: bigint, _stablecoin: bigint, _debt: bigint }> {
|
|
450
|
+
address = _getAddress(address);
|
|
451
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
452
|
+
const [_collateral, _stablecoin, _debt] = await contract.user_state(address, llamalend.constantOptions) as bigint[];
|
|
453
|
+
|
|
454
|
+
return { _collateral, _stablecoin, _debt }
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
public async userState(address = ""): Promise<{ collateral: string, stablecoin: string, debt: string }> {
|
|
458
|
+
const { _collateral, _stablecoin, _debt } = await this._userState(address);
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
collateral: formatUnits(_collateral, this.collateralDecimals),
|
|
462
|
+
stablecoin: formatUnits(_stablecoin),
|
|
463
|
+
debt: formatUnits(_debt),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
public async userLoss(userAddress = ""): Promise<{ deposited_collateral: string, current_collateral_estimation: string, loss: string, loss_pct: string }> {
|
|
468
|
+
userAddress = _getAddress(userAddress);
|
|
469
|
+
const [deposited_collateral, _current_collateral_estimation] = await Promise.all([
|
|
470
|
+
_getUserCollateralCrvUsd(llamalend.constants.NETWORK_NAME, this.controller, userAddress),
|
|
471
|
+
llamalend.contracts[this.address].contract.get_y_up(userAddress),
|
|
472
|
+
]);
|
|
473
|
+
const current_collateral_estimation = llamalend.formatUnits(_current_collateral_estimation, this.collateralDecimals);
|
|
474
|
+
|
|
475
|
+
if (BN(deposited_collateral).lte(0)) {
|
|
476
|
+
return {
|
|
477
|
+
deposited_collateral,
|
|
478
|
+
current_collateral_estimation,
|
|
479
|
+
loss: "0.0",
|
|
480
|
+
loss_pct: "0.0",
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
const loss = BN(deposited_collateral).minus(current_collateral_estimation).toString()
|
|
484
|
+
const loss_pct = BN(loss).div(deposited_collateral).times(100).toString();
|
|
485
|
+
|
|
486
|
+
return {
|
|
487
|
+
deposited_collateral,
|
|
488
|
+
current_collateral_estimation,
|
|
489
|
+
loss,
|
|
490
|
+
loss_pct,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public async userBandsBalances(address = ""): Promise<IDict<{ stablecoin: string, collateral: string }>> {
|
|
495
|
+
const [n2, n1] = await this.userBands(address);
|
|
496
|
+
if (n1 == 0 && n2 == 0) return {};
|
|
497
|
+
|
|
498
|
+
address = _getAddress(address);
|
|
499
|
+
const contract = llamalend.contracts[this.address].contract;
|
|
500
|
+
const [_stablecoins, _collaterals] = await contract.get_xy(address, llamalend.constantOptions) as [bigint[], bigint[]];
|
|
501
|
+
|
|
502
|
+
const res: IDict<{ stablecoin: string, collateral: string }> = {};
|
|
503
|
+
for (let i = n1; i <= n2; i++) {
|
|
504
|
+
res[i] = {
|
|
505
|
+
stablecoin: formatUnits(_stablecoins[i - n1], 18),
|
|
506
|
+
collateral: formatUnits(_collaterals[i - n1], this.collateralDecimals),
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return res
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
public async oraclePrice(): Promise<string> {
|
|
514
|
+
const _price = await llamalend.contracts[this.address].contract.price_oracle(llamalend.constantOptions) as bigint;
|
|
515
|
+
return formatUnits(_price);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
public async oraclePriceBand(): Promise<number> {
|
|
519
|
+
const oraclePriceBN = BN(await this.oraclePrice());
|
|
520
|
+
const basePriceBN = BN(await this.basePrice());
|
|
521
|
+
const A_BN = BN(this.A);
|
|
522
|
+
const multiplier = oraclePriceBN.lte(basePriceBN) ? A_BN.minus(1).div(A_BN) : A_BN.div(A_BN.minus(1));
|
|
523
|
+
const term = oraclePriceBN.lte(basePriceBN) ? 1 : -1;
|
|
524
|
+
const compareFunc = oraclePriceBN.lte(basePriceBN) ?
|
|
525
|
+
(oraclePriceBN: BigNumber, currentTickPriceBN: BigNumber) => oraclePriceBN.lte(currentTickPriceBN) :
|
|
526
|
+
(oraclePriceBN: BigNumber, currentTickPriceBN: BigNumber) => oraclePriceBN.gt(currentTickPriceBN);
|
|
527
|
+
|
|
528
|
+
let band = 0;
|
|
529
|
+
let currentTickPriceBN = oraclePriceBN.lte(basePriceBN) ? basePriceBN.times(multiplier) : basePriceBN;
|
|
530
|
+
while (compareFunc(oraclePriceBN, currentTickPriceBN)) {
|
|
531
|
+
currentTickPriceBN = currentTickPriceBN.times(multiplier);
|
|
532
|
+
band += term;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return band;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
public async price(): Promise<string> {
|
|
539
|
+
const _price = await llamalend.contracts[this.address].contract.get_p(llamalend.constantOptions) as bigint;
|
|
540
|
+
return formatUnits(_price);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
public basePrice = memoize(async(): Promise<string> => {
|
|
544
|
+
const _price = await llamalend.contracts[this.address].contract.get_base_price(llamalend.constantOptions) as bigint;
|
|
545
|
+
return formatUnits(_price);
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
promise: true,
|
|
549
|
+
maxAge: 60 * 1000, // 1m
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
public async calcTickPrice(n: number): Promise<string> {
|
|
553
|
+
const basePrice = await this.basePrice();
|
|
554
|
+
const basePriceBN = BN(basePrice);
|
|
555
|
+
const A_BN = BN(this.A);
|
|
556
|
+
|
|
557
|
+
return _cutZeros(basePriceBN.times(A_BN.minus(1).div(A_BN).pow(n)).toFixed(18))
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
public async calcBandPrices(n: number): Promise<[string, string]> {
|
|
561
|
+
return [await this.calcTickPrice(n + 1), await this.calcTickPrice(n)]
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
public calcRangePct(range: number): string {
|
|
565
|
+
/**
|
|
566
|
+
* Calculates range in terms of price difference %
|
|
567
|
+
* @param {number} range Number of bands in range
|
|
568
|
+
* @return {string} Range in %
|
|
569
|
+
*/
|
|
570
|
+
const A_BN = BN(this.A);
|
|
571
|
+
const startBN = BN(1);
|
|
572
|
+
const endBN = A_BN.minus(1).div(A_BN).pow(range);
|
|
573
|
+
|
|
574
|
+
return startBN.minus(endBN).times(100).toString()
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ---------------- WALLET BALANCES ----------------
|
|
578
|
+
|
|
579
|
+
private async walletBalances(address = ""): Promise<{ collateral: string, stablecoin: string }> {
|
|
580
|
+
const [collateral, stablecoin] = await getBalances([this.collateral, llamalend.address], address);
|
|
581
|
+
return { stablecoin, collateral }
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// ---------------- CREATE LOAN ----------------
|
|
585
|
+
|
|
586
|
+
private _checkRange(range: number): void {
|
|
587
|
+
if (range < this.minBands) throw Error(`range must be >= ${this.minBands}`);
|
|
588
|
+
if (range > this.maxBands) throw Error(`range must be <= ${this.maxBands}`);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
public async createLoanMaxRecv(collateral: number | string, range: number): Promise<string> {
|
|
592
|
+
this._checkRange(range);
|
|
593
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
594
|
+
|
|
595
|
+
return formatUnits(await llamalend.contracts[this.controller].contract.max_borrowable(_collateral, range, llamalend.constantOptions));
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
public createLoanMaxRecvAllRanges = memoize(async (collateral: number | string): Promise<{ [index: number]: string }> => {
|
|
599
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
600
|
+
|
|
601
|
+
const calls = [];
|
|
602
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
603
|
+
calls.push(llamalend.contracts[this.controller].multicallContract.max_borrowable(_collateral, N));
|
|
604
|
+
}
|
|
605
|
+
const _amounts = await llamalend.multicallProvider.all(calls) as bigint[];
|
|
606
|
+
|
|
607
|
+
const res: { [index: number]: string } = {};
|
|
608
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
609
|
+
res[N] = formatUnits(_amounts[N - this.minBands]);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return res;
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
promise: true,
|
|
616
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
public async getMaxRange(collateral: number | string, debt: number | string): Promise<number> {
|
|
620
|
+
const maxRecv = await this.createLoanMaxRecvAllRanges(collateral);
|
|
621
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
622
|
+
if (BN(debt).gt(BN(maxRecv[N]))) return N - 1;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
return this.maxBands;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private async _calcN1(_collateral: bigint, _debt: bigint, range: number): Promise<bigint> {
|
|
629
|
+
this._checkRange(range);
|
|
630
|
+
return await llamalend.contracts[this.controller].contract.calculate_debt_n1(_collateral, _debt, range, llamalend.constantOptions);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private async _calcN1AllRanges(_collateral: bigint, _debt: bigint, maxN: number): Promise<bigint[]> {
|
|
634
|
+
const calls = [];
|
|
635
|
+
for (let N = this.minBands; N <= maxN; N++) {
|
|
636
|
+
calls.push(llamalend.contracts[this.controller].multicallContract.calculate_debt_n1(_collateral, _debt, N));
|
|
637
|
+
}
|
|
638
|
+
return await llamalend.multicallProvider.all(calls) as bigint[];
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
private async _getPrices(_n2: bigint, _n1: bigint): Promise<string[]> {
|
|
642
|
+
const contract = llamalend.contracts[this.address].multicallContract;
|
|
643
|
+
return (await llamalend.multicallProvider.all([
|
|
644
|
+
contract.p_oracle_down(_n2),
|
|
645
|
+
contract.p_oracle_up(_n1),
|
|
646
|
+
]) as bigint[]).map((_p) => formatUnits(_p));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private async _calcPrices(_n2: bigint, _n1: bigint): Promise<[string, string]> {
|
|
650
|
+
return [await this.calcTickPrice(Number(_n2) + 1), await this.calcTickPrice(Number(_n1))];
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
private async _createLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[bigint, bigint]> {
|
|
654
|
+
const _n1 = await this._calcN1(parseUnits(collateral, this.collateralDecimals), parseUnits(debt), range);
|
|
655
|
+
const _n2 = _n1 + BigInt(range - 1);
|
|
656
|
+
|
|
657
|
+
return [_n2, _n1];
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
private async _createLoanBandsAllRanges(collateral: number | string, debt: number | string): Promise<{ [index: number]: [bigint, bigint] }> {
|
|
661
|
+
const maxN = await this.getMaxRange(collateral, debt);
|
|
662
|
+
const _n1_arr = await this._calcN1AllRanges(parseUnits(collateral, this.collateralDecimals), parseUnits(debt), maxN);
|
|
663
|
+
const _n2_arr: bigint[] = [];
|
|
664
|
+
for (let N = this.minBands; N <= maxN; N++) {
|
|
665
|
+
_n2_arr.push(_n1_arr[N - this.minBands] + BigInt(N - 1));
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const res: { [index: number]: [bigint, bigint] } = {};
|
|
669
|
+
for (let N = this.minBands; N <= maxN; N++) {
|
|
670
|
+
res[N] = [_n2_arr[N - this.minBands], _n1_arr[N - this.minBands]];
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return res;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
public async createLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[number, number]> {
|
|
677
|
+
const [_n2, _n1] = await this._createLoanBands(collateral, debt, range);
|
|
678
|
+
|
|
679
|
+
return [Number(_n2), Number(_n1)];
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
public async createLoanBandsAllRanges(collateral: number | string, debt: number | string): Promise<{ [index: number]: [number, number] | null }> {
|
|
683
|
+
const _bandsAllRanges = await this._createLoanBandsAllRanges(collateral, debt);
|
|
684
|
+
|
|
685
|
+
const bandsAllRanges: { [index: number]: [number, number] | null } = {};
|
|
686
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
687
|
+
if (_bandsAllRanges[N]) {
|
|
688
|
+
bandsAllRanges[N] = _bandsAllRanges[N].map(Number) as [number, number];
|
|
689
|
+
} else {
|
|
690
|
+
bandsAllRanges[N] = null
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return bandsAllRanges;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
public async createLoanPrices(collateral: number | string, debt: number | string, range: number): Promise<string[]> {
|
|
698
|
+
const [_n2, _n1] = await this._createLoanBands(collateral, debt, range);
|
|
699
|
+
|
|
700
|
+
return await this._getPrices(_n2, _n1);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
public async createLoanPricesAllRanges(collateral: number | string, debt: number | string): Promise<{ [index: number]: [string, string] | null }> {
|
|
704
|
+
const _bandsAllRanges = await this._createLoanBandsAllRanges(collateral, debt);
|
|
705
|
+
|
|
706
|
+
const pricesAllRanges: { [index: number]: [string, string] | null } = {};
|
|
707
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
708
|
+
if (_bandsAllRanges[N]) {
|
|
709
|
+
pricesAllRanges[N] = await this._calcPrices(..._bandsAllRanges[N]);
|
|
710
|
+
} else {
|
|
711
|
+
pricesAllRanges[N] = null
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
return pricesAllRanges;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
public async createLoanHealth(collateral: number | string, debt: number | string, range: number, full = true, address = ""): Promise<string> {
|
|
719
|
+
address = _getAddress(address);
|
|
720
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
721
|
+
const _debt = parseUnits(debt);
|
|
722
|
+
|
|
723
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
724
|
+
let _health = await contract.health_calculator(address, _collateral, _debt, full, range, llamalend.constantOptions) as bigint;
|
|
725
|
+
_health = _health * BigInt(100);
|
|
726
|
+
|
|
727
|
+
return formatUnits(_health);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
public async createLoanIsApproved(collateral: number | string): Promise<boolean> {
|
|
731
|
+
return await hasAllowance([this.collateral], [collateral], llamalend.signerAddress, this.controller);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
private async createLoanApproveEstimateGas (collateral: number | string): Promise<TGas> {
|
|
735
|
+
return await ensureAllowanceEstimateGas([this.collateral], [collateral], this.controller);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
public async createLoanApprove(collateral: number | string): Promise<string[]> {
|
|
739
|
+
return await ensureAllowance([this.collateral], [collateral], this.controller);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
private async _createLoan(collateral: number | string, debt: number | string, range: number, estimateGas: boolean): Promise<string | TGas> {
|
|
743
|
+
if (await this.loanExists()) throw Error("Loan already created");
|
|
744
|
+
this._checkRange(range);
|
|
745
|
+
|
|
746
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
747
|
+
const _debt = parseUnits(debt);
|
|
748
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
749
|
+
const value = isEth(this.collateral) ? _collateral : llamalend.parseUnits("0");
|
|
750
|
+
const gas = await contract.create_loan.estimateGas(_collateral, _debt, range, { ...llamalend.constantOptions, value });
|
|
751
|
+
if (estimateGas) return smartNumber(gas);
|
|
752
|
+
|
|
753
|
+
await llamalend.updateFeeData();
|
|
754
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
755
|
+
return (await contract.create_loan(_collateral, _debt, range, { ...llamalend.options, gasLimit, value })).hash
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
public async createLoanEstimateGas(collateral: number | string, debt: number | string, range: number): Promise<number> {
|
|
759
|
+
if (!(await this.createLoanIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
|
|
760
|
+
return await this._createLoan(collateral, debt, range, true) as number;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
public async createLoan(collateral: number | string, debt: number | string, range: number): Promise<string> {
|
|
764
|
+
await this.createLoanApprove(collateral);
|
|
765
|
+
return await this._createLoan(collateral, debt, range, false) as string;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// ---------------- BORROW MORE ----------------
|
|
769
|
+
|
|
770
|
+
public async borrowMoreMaxRecv(collateralAmount: number | string): Promise<string> {
|
|
771
|
+
const { _collateral: _currentCollateral, _debt: _currentDebt } = await this._userState();
|
|
772
|
+
const N = await this.userRange();
|
|
773
|
+
const _collateral = _currentCollateral + parseUnits(collateralAmount, this.collateralDecimals);
|
|
774
|
+
|
|
775
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
776
|
+
const _debt: bigint = await contract.max_borrowable(_collateral, N, llamalend.constantOptions);
|
|
777
|
+
|
|
778
|
+
return formatUnits(_debt - _currentDebt);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
private async _borrowMoreBands(collateral: number | string, debt: number | string): Promise<[bigint, bigint]> {
|
|
782
|
+
const { _collateral: _currentCollateral, _debt: _currentDebt } = await this._userState();
|
|
783
|
+
if (_currentDebt === BigInt(0)) throw Error(`Loan for ${llamalend.signerAddress} does not exist`);
|
|
784
|
+
|
|
785
|
+
const N = await this.userRange();
|
|
786
|
+
const _collateral = _currentCollateral + parseUnits(collateral, this.collateralDecimals);
|
|
787
|
+
const _debt = _currentDebt + parseUnits(debt);
|
|
788
|
+
|
|
789
|
+
const _n1 = await this._calcN1(_collateral, _debt, N);
|
|
790
|
+
const _n2 = _n1 + BigInt(N - 1);
|
|
791
|
+
|
|
792
|
+
return [_n2, _n1];
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
public async borrowMoreBands(collateral: number | string, debt: number | string): Promise<[number, number]> {
|
|
796
|
+
const [_n2, _n1] = await this._borrowMoreBands(collateral, debt);
|
|
797
|
+
|
|
798
|
+
return [Number(_n2), Number(_n1)];
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
public async borrowMorePrices(collateral: number | string, debt: number | string): Promise<string[]> {
|
|
802
|
+
const [_n2, _n1] = await this._borrowMoreBands(collateral, debt);
|
|
803
|
+
|
|
804
|
+
return await this._getPrices(_n2, _n1);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
public async borrowMoreHealth(collateral: number | string, debt: number | string, full = true, address = ""): Promise<string> {
|
|
808
|
+
address = _getAddress(address);
|
|
809
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
810
|
+
const _debt = parseUnits(debt);
|
|
811
|
+
|
|
812
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
813
|
+
let _health = await contract.health_calculator(address, _collateral, _debt, full, 0, llamalend.constantOptions) as bigint;
|
|
814
|
+
_health = _health * BigInt(100);
|
|
815
|
+
|
|
816
|
+
return formatUnits(_health);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
public async borrowMoreIsApproved(collateral: number | string): Promise<boolean> {
|
|
820
|
+
return await hasAllowance([this.collateral], [collateral], llamalend.signerAddress, this.controller);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
private async borrowMoreApproveEstimateGas (collateral: number | string): Promise<TGas> {
|
|
824
|
+
return await ensureAllowanceEstimateGas([this.collateral], [collateral], this.controller);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
public async borrowMoreApprove(collateral: number | string): Promise<string[]> {
|
|
828
|
+
return await ensureAllowance([this.collateral], [collateral], this.controller);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
private async _borrowMore(collateral: number | string, debt: number | string, estimateGas: boolean): Promise<string | TGas> {
|
|
832
|
+
const { stablecoin, debt: currentDebt } = await this.userState();
|
|
833
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${llamalend.signerAddress} does not exist`);
|
|
834
|
+
if (Number(stablecoin) > 0) throw Error(`User ${llamalend.signerAddress} is already in liquidation mode`);
|
|
835
|
+
|
|
836
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
837
|
+
const _debt = parseUnits(debt);
|
|
838
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
839
|
+
const value = isEth(this.collateral) ? _collateral : llamalend.parseUnits("0");
|
|
840
|
+
const gas = await contract.borrow_more.estimateGas(_collateral, _debt, { ...llamalend.constantOptions, value });
|
|
841
|
+
if (estimateGas) return smartNumber(gas);
|
|
842
|
+
|
|
843
|
+
await llamalend.updateFeeData();
|
|
844
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
845
|
+
return (await contract.borrow_more(_collateral, _debt, { ...llamalend.options, gasLimit, value })).hash
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
public async borrowMoreEstimateGas(collateral: number | string, debt: number | string): Promise<number> {
|
|
849
|
+
if (!(await this.borrowMoreIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
|
|
850
|
+
return await this._borrowMore(collateral, debt, true) as number;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
public async borrowMore(collateral: number | string, debt: number | string): Promise<string> {
|
|
854
|
+
await this.borrowMoreApprove(collateral);
|
|
855
|
+
return await this._borrowMore(collateral, debt, false) as string;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// ---------------- ADD COLLATERAL ----------------
|
|
859
|
+
|
|
860
|
+
private async _addCollateralBands(collateral: number | string, address = ""): Promise<[bigint, bigint]> {
|
|
861
|
+
address = _getAddress(address);
|
|
862
|
+
const { _collateral: _currentCollateral, _debt: _currentDebt } = await this._userState(address);
|
|
863
|
+
if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
|
|
864
|
+
|
|
865
|
+
const N = await this.userRange(address);
|
|
866
|
+
const _collateral = _currentCollateral + parseUnits(collateral, this.collateralDecimals);
|
|
867
|
+
const _n1 = await this._calcN1(_collateral, _currentDebt, N);
|
|
868
|
+
const _n2 = _n1 + BigInt(N - 1);
|
|
869
|
+
|
|
870
|
+
return [_n2, _n1];
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
public async addCollateralBands(collateral: number | string, address = ""): Promise<[number, number]> {
|
|
874
|
+
const [_n2, _n1] = await this._addCollateralBands(collateral, address);
|
|
875
|
+
|
|
876
|
+
return [Number(_n2), Number(_n1)];
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
public async addCollateralPrices(collateral: number | string, address = ""): Promise<string[]> {
|
|
880
|
+
const [_n2, _n1] = await this._addCollateralBands(collateral, address);
|
|
881
|
+
|
|
882
|
+
return await this._getPrices(_n2, _n1);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
public async addCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
|
|
886
|
+
address = _getAddress(address);
|
|
887
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
888
|
+
|
|
889
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
890
|
+
let _health = await contract.health_calculator(address, _collateral, 0, full, 0, llamalend.constantOptions) as bigint;
|
|
891
|
+
_health = _health * BigInt(100);
|
|
892
|
+
|
|
893
|
+
return formatUnits(_health);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
public async addCollateralIsApproved(collateral: number | string): Promise<boolean> {
|
|
897
|
+
return await hasAllowance([this.collateral], [collateral], llamalend.signerAddress, this.controller);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
private async addCollateralApproveEstimateGas (collateral: number | string): Promise<TGas> {
|
|
901
|
+
return await ensureAllowanceEstimateGas([this.collateral], [collateral], this.controller);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
public async addCollateralApprove(collateral: number | string): Promise<string[]> {
|
|
905
|
+
return await ensureAllowance([this.collateral], [collateral], this.controller);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private async _addCollateral(collateral: number | string, address: string, estimateGas: boolean): Promise<string | TGas> {
|
|
909
|
+
const { stablecoin, debt: currentDebt } = await this.userState(address);
|
|
910
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
|
|
911
|
+
if (Number(stablecoin) > 0) throw Error(`User ${address} is already in liquidation mode`);
|
|
912
|
+
|
|
913
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
914
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
915
|
+
const value = isEth(this.collateral) ? _collateral : llamalend.parseUnits("0");
|
|
916
|
+
const gas = await contract.add_collateral.estimateGas(_collateral, address, { ...llamalend.constantOptions, value });
|
|
917
|
+
if (estimateGas) return smartNumber(gas);
|
|
918
|
+
|
|
919
|
+
await llamalend.updateFeeData();
|
|
920
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
921
|
+
return (await contract.add_collateral(_collateral, address, { ...llamalend.options, gasLimit, value })).hash
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
public async addCollateralEstimateGas(collateral: number | string, address = ""): Promise<number> {
|
|
925
|
+
address = _getAddress(address);
|
|
926
|
+
if (!(await this.addCollateralIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
|
|
927
|
+
return await this._addCollateral(collateral, address, true) as number;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
public async addCollateral(collateral: number | string, address = ""): Promise<string> {
|
|
931
|
+
address = _getAddress(address);
|
|
932
|
+
await this.addCollateralApprove(collateral);
|
|
933
|
+
return await this._addCollateral(collateral, address, false) as string;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// ---------------- REMOVE COLLATERAL ----------------
|
|
937
|
+
|
|
938
|
+
public async maxRemovable(): Promise<string> {
|
|
939
|
+
const { _collateral: _currentCollateral, _debt: _currentDebt } = await this._userState();
|
|
940
|
+
const N = await this.userRange();
|
|
941
|
+
const _requiredCollateral = await llamalend.contracts[this.controller].contract.min_collateral(_currentDebt, N, llamalend.constantOptions)
|
|
942
|
+
|
|
943
|
+
return formatUnits(_currentCollateral - _requiredCollateral, this.collateralDecimals);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
private async _removeCollateralBands(collateral: number | string): Promise<[bigint, bigint]> {
|
|
947
|
+
const { _collateral: _currentCollateral, _debt: _currentDebt } = await this._userState();
|
|
948
|
+
if (_currentDebt === BigInt(0)) throw Error(`Loan for ${llamalend.signerAddress} does not exist`);
|
|
949
|
+
|
|
950
|
+
const N = await this.userRange();
|
|
951
|
+
const _collateral = _currentCollateral - parseUnits(collateral, this.collateralDecimals);
|
|
952
|
+
const _n1 = await this._calcN1(_collateral, _currentDebt, N);
|
|
953
|
+
const _n2 = _n1 + BigInt(N - 1);
|
|
954
|
+
|
|
955
|
+
return [_n2, _n1];
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
public async removeCollateralBands(collateral: number | string): Promise<[number, number]> {
|
|
959
|
+
const [_n2, _n1] = await this._removeCollateralBands(collateral);
|
|
960
|
+
|
|
961
|
+
return [Number(_n2), Number(_n1)];
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
public async removeCollateralPrices(collateral: number | string): Promise<string[]> {
|
|
965
|
+
const [_n2, _n1] = await this._removeCollateralBands(collateral);
|
|
966
|
+
|
|
967
|
+
return await this._getPrices(_n2, _n1);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
public async removeCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
|
|
971
|
+
address = _getAddress(address);
|
|
972
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals) * BigInt(-1);
|
|
973
|
+
|
|
974
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
975
|
+
let _health = await contract.health_calculator(address, _collateral, 0, full, 0, llamalend.constantOptions) as bigint;
|
|
976
|
+
_health = _health * BigInt(100);
|
|
977
|
+
|
|
978
|
+
return formatUnits(_health);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
private async _removeCollateral(collateral: number | string, estimateGas: boolean): Promise<string | TGas> {
|
|
982
|
+
const { stablecoin, debt: currentDebt } = await this.userState();
|
|
983
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${llamalend.signerAddress} does not exist`);
|
|
984
|
+
if (Number(stablecoin) > 0) throw Error(`User ${llamalend.signerAddress} is already in liquidation mode`);
|
|
985
|
+
|
|
986
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
987
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
988
|
+
const gas = await contract.remove_collateral.estimateGas(_collateral, isEth(this.collateral), llamalend.constantOptions);
|
|
989
|
+
if (estimateGas) return smartNumber(gas);
|
|
990
|
+
|
|
991
|
+
await llamalend.updateFeeData();
|
|
992
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
993
|
+
return (await contract.remove_collateral(_collateral, isEth(this.collateral), { ...llamalend.options, gasLimit })).hash
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
public async removeCollateralEstimateGas(collateral: number | string): Promise<number> {
|
|
997
|
+
return await this._removeCollateral(collateral, true) as number;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
public async removeCollateral(collateral: number | string): Promise<string> {
|
|
1001
|
+
return await this._removeCollateral(collateral, false) as string;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// ---------------- REPAY ----------------
|
|
1005
|
+
|
|
1006
|
+
private async _repayBands(debt: number | string, address: string): Promise<[bigint, bigint]> {
|
|
1007
|
+
const { _collateral: _currentCollateral, _debt: _currentDebt, _stablecoin: _currentStablecoin } = await this._userState(address);
|
|
1008
|
+
if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
|
|
1009
|
+
|
|
1010
|
+
const N = await this.userRange(address);
|
|
1011
|
+
const _debt = _currentDebt - parseUnits(debt);
|
|
1012
|
+
const _n1 = _currentStablecoin === BigInt(0) ? await this._calcN1(_currentCollateral, _debt, N) : (await llamalend.contracts[this.address].contract.read_user_tick_numbers(address, llamalend.constantOptions) as bigint[])[0];
|
|
1013
|
+
const _n2 = _n1 + BigInt(N - 1);
|
|
1014
|
+
|
|
1015
|
+
return [_n2, _n1];
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
public async repayBands(debt: number | string, address = ""): Promise<[number, number]> {
|
|
1019
|
+
const [_n2, _n1] = await this._repayBands(debt, address);
|
|
1020
|
+
|
|
1021
|
+
return [Number(_n2), Number(_n1)];
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
public async repayPrices(debt: number | string, address = ""): Promise<string[]> {
|
|
1025
|
+
const [_n2, _n1] = await this._repayBands(debt, address);
|
|
1026
|
+
|
|
1027
|
+
return await this._getPrices(_n2, _n1);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
public async repayIsApproved(debt: number | string): Promise<boolean> {
|
|
1031
|
+
return await hasAllowance([llamalend.address], [debt], llamalend.signerAddress, this.controller);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
private async repayApproveEstimateGas (debt: number | string): Promise<TGas> {
|
|
1035
|
+
return await ensureAllowanceEstimateGas([llamalend.address], [debt], this.controller);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
public async repayApprove(debt: number | string): Promise<string[]> {
|
|
1039
|
+
return await ensureAllowance([llamalend.address], [debt], this.controller);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
public async repayHealth(debt: number | string, full = true, address = ""): Promise<string> {
|
|
1043
|
+
address = _getAddress(address);
|
|
1044
|
+
const _debt = parseUnits(debt) * BigInt(-1);
|
|
1045
|
+
|
|
1046
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
1047
|
+
let _health = await contract.health_calculator(address, 0, _debt, full, 0, llamalend.constantOptions) as bigint;
|
|
1048
|
+
_health = _health * BigInt(100);
|
|
1049
|
+
|
|
1050
|
+
return formatUnits(_health);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
private async _repay(debt: number | string, address: string, estimateGas: boolean): Promise<string | TGas> {
|
|
1054
|
+
address = _getAddress(address);
|
|
1055
|
+
const { debt: currentDebt } = await this.userState(address);
|
|
1056
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
|
|
1057
|
+
|
|
1058
|
+
const _debt = parseUnits(debt);
|
|
1059
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
1060
|
+
const [_, n1] = await this.userBands(address);
|
|
1061
|
+
const { stablecoin } = await this.userState(address);
|
|
1062
|
+
const n = (BN(stablecoin).gt(0)) ? MAX_ACTIVE_BAND : n1 - 1; // In liquidation mode it doesn't matter if active band moves
|
|
1063
|
+
const gas = await contract.repay.estimateGas(_debt, address, n, isEth(this.collateral), llamalend.constantOptions);
|
|
1064
|
+
if (estimateGas) return smartNumber(gas);
|
|
1065
|
+
|
|
1066
|
+
await llamalend.updateFeeData();
|
|
1067
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
1068
|
+
return (await contract.repay(_debt, address, n, isEth(this.collateral), { ...llamalend.options, gasLimit })).hash
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
public async repayEstimateGas(debt: number | string, address = ""): Promise<number> {
|
|
1072
|
+
if (!(await this.repayIsApproved(debt))) throw Error("Approval is needed for gas estimation");
|
|
1073
|
+
return await this._repay(debt, address, true) as number;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
public async repay(debt: number | string, address = ""): Promise<string> {
|
|
1077
|
+
await this.repayApprove(debt);
|
|
1078
|
+
return await this._repay(debt, address, false) as string;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// ---------------- FULL REPAY ----------------
|
|
1082
|
+
|
|
1083
|
+
private async _fullRepayAmount(address = ""): Promise<string> {
|
|
1084
|
+
address = _getAddress(address);
|
|
1085
|
+
const debt = await this.userDebt(address);
|
|
1086
|
+
return BN(debt).times(1.0001).toString();
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
public async fullRepayIsApproved(address = ""): Promise<boolean> {
|
|
1090
|
+
address = _getAddress(address);
|
|
1091
|
+
const fullRepayAmount = await this._fullRepayAmount(address);
|
|
1092
|
+
return await this.repayIsApproved(fullRepayAmount);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
private async fullRepayApproveEstimateGas (address = ""): Promise<TGas> {
|
|
1096
|
+
address = _getAddress(address);
|
|
1097
|
+
const fullRepayAmount = await this._fullRepayAmount(address);
|
|
1098
|
+
return await this.repayApproveEstimateGas(fullRepayAmount);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
public async fullRepayApprove(address = ""): Promise<string[]> {
|
|
1102
|
+
address = _getAddress(address);
|
|
1103
|
+
const fullRepayAmount = await this._fullRepayAmount(address);
|
|
1104
|
+
return await this.repayApprove(fullRepayAmount);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
public async fullRepayEstimateGas(address = ""): Promise<number> {
|
|
1108
|
+
address = _getAddress(address);
|
|
1109
|
+
const fullRepayAmount = await this._fullRepayAmount(address);
|
|
1110
|
+
if (!(await this.repayIsApproved(fullRepayAmount))) throw Error("Approval is needed for gas estimation");
|
|
1111
|
+
return await this._repay(fullRepayAmount, address, true) as number;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
public async fullRepay(address = ""): Promise<string> {
|
|
1115
|
+
address = _getAddress(address);
|
|
1116
|
+
const fullRepayAmount = await this._fullRepayAmount(address);
|
|
1117
|
+
await this.repayApprove(fullRepayAmount);
|
|
1118
|
+
return await this._repay(fullRepayAmount, address, false) as string;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// ---------------- SWAP ----------------
|
|
1122
|
+
|
|
1123
|
+
public async maxSwappable(i: number, j: number): Promise<string> {
|
|
1124
|
+
if (!(i === 0 && j === 1) && !(i === 1 && j === 0)) throw Error("Wrong index");
|
|
1125
|
+
const inDecimals = this.coinDecimals[i];
|
|
1126
|
+
const contract = llamalend.contracts[this.address].contract;
|
|
1127
|
+
const [_inAmount, _outAmount] = await contract.get_dxdy(i, j, MAX_ALLOWANCE, llamalend.constantOptions) as bigint[];
|
|
1128
|
+
if (_outAmount === BigInt(0)) return "0";
|
|
1129
|
+
|
|
1130
|
+
return formatUnits(_inAmount, inDecimals)
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
private async _swapExpected(i: number, j: number, _amount: bigint): Promise<bigint> {
|
|
1134
|
+
return await llamalend.contracts[this.address].contract.get_dy(i, j, _amount, llamalend.constantOptions) as bigint;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
public async swapExpected(i: number, j: number, amount: number | string): Promise<string> {
|
|
1138
|
+
if (!(i === 0 && j === 1) && !(i === 1 && j === 0)) throw Error("Wrong index");
|
|
1139
|
+
const [inDecimals, outDecimals] = this.coinDecimals;
|
|
1140
|
+
const _amount = parseUnits(amount, inDecimals);
|
|
1141
|
+
const _expected = await this._swapExpected(i, j, _amount);
|
|
1142
|
+
|
|
1143
|
+
return formatUnits(_expected, outDecimals)
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
public async swapRequired(i: number, j: number, outAmount: number | string): Promise<string> {
|
|
1147
|
+
if (!(i === 0 && j === 1) && !(i === 1 && j === 0)) throw Error("Wrong index");
|
|
1148
|
+
const [inDecimals, outDecimals] = this.coinDecimals;
|
|
1149
|
+
const _amount = parseUnits(outAmount, outDecimals);
|
|
1150
|
+
const _expected = await llamalend.contracts[this.address].contract.get_dx(i, j, _amount, llamalend.constantOptions) as bigint;
|
|
1151
|
+
|
|
1152
|
+
return formatUnits(_expected, inDecimals)
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
public async swapPriceImpact(i: number, j: number, amount: number | string): Promise<string> {
|
|
1156
|
+
if (!(i === 0 && j === 1) && !(i === 1 && j === 0)) throw Error("Wrong index");
|
|
1157
|
+
const [inDecimals, outDecimals] = this.coinDecimals;
|
|
1158
|
+
const _amount = parseUnits(amount, inDecimals);
|
|
1159
|
+
const _output = await this._swapExpected(i, j, _amount);
|
|
1160
|
+
|
|
1161
|
+
// Find k for which x * k = 10^15 or y * k = 10^15: k = max(10^15 / x, 10^15 / y)
|
|
1162
|
+
// For coins with d (decimals) <= 15: k = min(k, 0.2), and x0 = min(x * k, 10^d)
|
|
1163
|
+
// x0 = min(x * min(max(10^15 / x, 10^15 / y), 0.2), 10^d), if x0 == 0 then priceImpact = 0
|
|
1164
|
+
const target = BN(10 ** 15);
|
|
1165
|
+
const amountIntBN = BN(amount).times(10 ** inDecimals);
|
|
1166
|
+
const outputIntBN = toBN(_output, 0);
|
|
1167
|
+
const k = BigNumber.min(BigNumber.max(target.div(amountIntBN), target.div(outputIntBN)), 0.2);
|
|
1168
|
+
const smallAmountIntBN = BigNumber.min(amountIntBN.times(k), BN(10 ** inDecimals));
|
|
1169
|
+
if (smallAmountIntBN.toFixed(0) === '0') return '0';
|
|
1170
|
+
|
|
1171
|
+
const _smallAmount = fromBN(smallAmountIntBN.div(10 ** inDecimals), inDecimals);
|
|
1172
|
+
const _smallOutput = await this._swapExpected(i, j, _smallAmount);
|
|
1173
|
+
|
|
1174
|
+
const amountBN = BN(amount);
|
|
1175
|
+
const outputBN = toBN(_output, outDecimals);
|
|
1176
|
+
const smallAmountBN = toBN(_smallAmount, inDecimals);
|
|
1177
|
+
const smallOutputBN = toBN(_smallOutput, outDecimals);
|
|
1178
|
+
|
|
1179
|
+
const rateBN = outputBN.div(amountBN);
|
|
1180
|
+
const smallRateBN = smallOutputBN.div(smallAmountBN);
|
|
1181
|
+
if (rateBN.gt(smallRateBN)) return "0";
|
|
1182
|
+
|
|
1183
|
+
const slippageBN = BN(1).minus(rateBN.div(smallRateBN)).times(100);
|
|
1184
|
+
|
|
1185
|
+
return _cutZeros(slippageBN.toFixed(6));
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
public async swapIsApproved(i: number, amount: number | string): Promise<boolean> {
|
|
1189
|
+
if (i !== 0 && i !== 1) throw Error("Wrong index");
|
|
1190
|
+
|
|
1191
|
+
return await hasAllowance([this.coinAddresses[i]], [amount], llamalend.signerAddress, this.address);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
private async swapApproveEstimateGas (i: number, amount: number | string): Promise<TGas> {
|
|
1195
|
+
if (i !== 0 && i !== 1) throw Error("Wrong index");
|
|
1196
|
+
|
|
1197
|
+
return await ensureAllowanceEstimateGas([this.coinAddresses[i]], [amount], this.address);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
public async swapApprove(i: number, amount: number | string): Promise<string[]> {
|
|
1201
|
+
if (i !== 0 && i !== 1) throw Error("Wrong index");
|
|
1202
|
+
|
|
1203
|
+
return await ensureAllowance([this.coinAddresses[i]], [amount], this.address);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
private async _swap(i: number, j: number, amount: number | string, slippage: number, estimateGas: boolean): Promise<string | TGas> {
|
|
1207
|
+
if (!(i === 0 && j === 1) && !(i === 1 && j === 0)) throw Error("Wrong index");
|
|
1208
|
+
|
|
1209
|
+
const [inDecimals, outDecimals] = [this.coinDecimals[i], this.coinDecimals[j]];
|
|
1210
|
+
const _amount = parseUnits(amount, inDecimals);
|
|
1211
|
+
const _expected = await this._swapExpected(i, j, _amount);
|
|
1212
|
+
const minRecvAmountBN: BigNumber = toBN(_expected, outDecimals).times(100 - slippage).div(100);
|
|
1213
|
+
const _minRecvAmount = fromBN(minRecvAmountBN, outDecimals);
|
|
1214
|
+
const contract = llamalend.contracts[this.address].contract;
|
|
1215
|
+
const gas = await contract.exchange.estimateGas(i, j, _amount, _minRecvAmount, llamalend.constantOptions);
|
|
1216
|
+
if (estimateGas) return smartNumber(gas);
|
|
1217
|
+
|
|
1218
|
+
await llamalend.updateFeeData();
|
|
1219
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
1220
|
+
return (await contract.exchange(i, j, _amount, _minRecvAmount, { ...llamalend.options, gasLimit })).hash
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
public async swapEstimateGas(i: number, j: number, amount: number | string, slippage = 0.1): Promise<number> {
|
|
1224
|
+
if (!(await this.swapIsApproved(i, amount))) throw Error("Approval is needed for gas estimation");
|
|
1225
|
+
return await this._swap(i, j, amount, slippage, true) as number;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
public async swap(i: number, j: number, amount: number | string, slippage = 0.1): Promise<string> {
|
|
1229
|
+
await this.swapApprove(i, amount);
|
|
1230
|
+
return await this._swap(i, j, amount, slippage, false) as string;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// ---------------- LIQUIDATE ----------------
|
|
1234
|
+
|
|
1235
|
+
public async tokensToLiquidate(address = ""): Promise<string> {
|
|
1236
|
+
address = _getAddress(address);
|
|
1237
|
+
const _tokens = await llamalend.contracts[this.controller].contract.tokens_to_liquidate(address, llamalend.constantOptions) as bigint;
|
|
1238
|
+
|
|
1239
|
+
return formatUnits(_tokens)
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
public async liquidateIsApproved(address = ""): Promise<boolean> {
|
|
1243
|
+
const tokensToLiquidate = await this.tokensToLiquidate(address);
|
|
1244
|
+
return await hasAllowance([llamalend.address], [tokensToLiquidate], llamalend.signerAddress, this.controller);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
private async liquidateApproveEstimateGas (address = ""): Promise<TGas> {
|
|
1248
|
+
const tokensToLiquidate = await this.tokensToLiquidate(address);
|
|
1249
|
+
return await ensureAllowanceEstimateGas([llamalend.address], [tokensToLiquidate], this.controller);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
public async liquidateApprove(address = ""): Promise<string[]> {
|
|
1253
|
+
const tokensToLiquidate = await this.tokensToLiquidate(address);
|
|
1254
|
+
return await ensureAllowance([llamalend.address], [tokensToLiquidate], this.controller);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
private async _liquidate(address: string, slippage: number, estimateGas: boolean): Promise<string | TGas> {
|
|
1258
|
+
const { stablecoin, debt: currentDebt } = await this.userState(address);
|
|
1259
|
+
if (slippage <= 0) throw Error("Slippage must be > 0");
|
|
1260
|
+
if (slippage > 100) throw Error("Slippage must be <= 100");
|
|
1261
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
|
|
1262
|
+
if (Number(stablecoin) === 0) throw Error(`User ${address} is not in liquidation mode`);
|
|
1263
|
+
|
|
1264
|
+
const minAmountBN: BigNumber = BN(stablecoin).times(100 - slippage).div(100);
|
|
1265
|
+
const _minAmount = fromBN(minAmountBN);
|
|
1266
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
1267
|
+
const gas = (await contract.liquidate.estimateGas(address, _minAmount, isEth(this.collateral), llamalend.constantOptions))
|
|
1268
|
+
if (estimateGas) return smartNumber(gas);
|
|
1269
|
+
|
|
1270
|
+
await llamalend.updateFeeData();
|
|
1271
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
1272
|
+
return (await contract.liquidate(address, _minAmount, isEth(this.collateral), { ...llamalend.options, gasLimit })).hash
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
public async liquidateEstimateGas(address: string, slippage = 0.1): Promise<number> {
|
|
1276
|
+
if (!(await this.liquidateIsApproved(address))) throw Error("Approval is needed for gas estimation");
|
|
1277
|
+
return await this._liquidate(address, slippage, true) as number;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
public async liquidate(address: string, slippage = 0.1): Promise<string> {
|
|
1281
|
+
await this.liquidateApprove(address);
|
|
1282
|
+
return await this._liquidate(address, slippage, false) as string;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// ---------------- SELF-LIQUIDATE ----------------
|
|
1286
|
+
|
|
1287
|
+
public async selfLiquidateIsApproved(): Promise<boolean> {
|
|
1288
|
+
return await this.liquidateIsApproved()
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
private async selfLiquidateApproveEstimateGas (): Promise<TGas> {
|
|
1292
|
+
return this.liquidateApproveEstimateGas()
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
public async selfLiquidateApprove(): Promise<string[]> {
|
|
1296
|
+
return await this.liquidateApprove()
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
public async selfLiquidateEstimateGas(slippage = 0.1): Promise<number> {
|
|
1300
|
+
if (!(await this.selfLiquidateIsApproved())) throw Error("Approval is needed for gas estimation");
|
|
1301
|
+
return await this._liquidate(llamalend.signerAddress, slippage, true) as number;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
public async selfLiquidate(slippage = 0.1): Promise<string> {
|
|
1305
|
+
await this.selfLiquidateApprove();
|
|
1306
|
+
return await this._liquidate(llamalend.signerAddress, slippage, false) as string;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// ---------------- CREATE LOAN WITH LEVERAGE ----------------
|
|
1310
|
+
|
|
1311
|
+
private _getBestIdx(_amounts: bigint[]): number {
|
|
1312
|
+
let bestIdx = 0;
|
|
1313
|
+
for (let i = 1; i < 5; i++) {
|
|
1314
|
+
if (_amounts[i] > _amounts[bestIdx]) bestIdx = i;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
return bestIdx
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
private _checkLeverageZap(): void {
|
|
1321
|
+
if (this.leverageZap === "0x0000000000000000000000000000000000000000") throw Error(`There is no leverage for ${this.id} market`)
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
private async leverageCreateLoanMaxRecv(collateral: number | string, range: number):
|
|
1325
|
+
Promise<{ maxBorrowable: string, maxCollateral: string, leverage: string, routeIdx: number }> {
|
|
1326
|
+
this._checkLeverageZap();
|
|
1327
|
+
this._checkRange(range);
|
|
1328
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1329
|
+
const calls = [];
|
|
1330
|
+
for (let i = 0; i < 5; i++) {
|
|
1331
|
+
calls.push(llamalend.contracts[this.leverageZap].multicallContract.max_borrowable_and_collateral(_collateral, range, i));
|
|
1332
|
+
}
|
|
1333
|
+
const _res: bigint[][] = await llamalend.multicallProvider.all(calls);
|
|
1334
|
+
const _maxBorrowable = _res.map((r) => r[0] * BigInt(999) / BigInt(1000));
|
|
1335
|
+
const _maxCollateral = _res.map((r) => r[1] * BigInt(999) / BigInt(1000));
|
|
1336
|
+
const routeIdx = this._getBestIdx(_maxCollateral);
|
|
1337
|
+
|
|
1338
|
+
const maxBorrowable = llamalend.formatUnits(_maxBorrowable[routeIdx]);
|
|
1339
|
+
const maxCollateral = llamalend.formatUnits(_maxCollateral[routeIdx], this.collateralDecimals);
|
|
1340
|
+
return {
|
|
1341
|
+
maxBorrowable,
|
|
1342
|
+
maxCollateral,
|
|
1343
|
+
leverage: BN(maxCollateral).div(collateral).toFixed(4),
|
|
1344
|
+
routeIdx,
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
private leverageCreateLoanMaxRecvAllRanges = memoize(async (collateral: number | string):
|
|
1349
|
+
Promise<IDict<{ maxBorrowable: string, maxCollateral: string, leverage: string, routeIdx: number }>> => {
|
|
1350
|
+
this._checkLeverageZap();
|
|
1351
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1352
|
+
|
|
1353
|
+
const calls = [];
|
|
1354
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1355
|
+
for (let i = 0; i < 5; i++) {
|
|
1356
|
+
calls.push(llamalend.contracts[this.leverageZap].multicallContract.max_borrowable_and_collateral(_collateral, N, i));
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
const _rawRes: bigint[][] = await llamalend.multicallProvider.all(calls);
|
|
1360
|
+
|
|
1361
|
+
const res: IDict<{ maxBorrowable: string, maxCollateral: string, leverage: string, routeIdx: number }> = {};
|
|
1362
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1363
|
+
const _res = _rawRes.splice(0, 5);
|
|
1364
|
+
const _maxBorrowable = _res.map((r) => r[0] * BigInt(999) / BigInt(1000));
|
|
1365
|
+
const _maxCollateral = _res.map((r) => r[1] * BigInt(999) / BigInt(1000));
|
|
1366
|
+
const routeIdx = this._getBestIdx(_maxCollateral);
|
|
1367
|
+
const maxBorrowable = llamalend.formatUnits(_maxBorrowable[routeIdx]);
|
|
1368
|
+
const maxCollateral = llamalend.formatUnits(_maxCollateral[routeIdx], this.collateralDecimals);
|
|
1369
|
+
res[N] = {
|
|
1370
|
+
maxBorrowable,
|
|
1371
|
+
maxCollateral,
|
|
1372
|
+
leverage: BN(maxCollateral).div(collateral).toFixed(4),
|
|
1373
|
+
routeIdx,
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
return res;
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
promise: true,
|
|
1381
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1384
|
+
private _leverageCreateLoanMaxRecvAllRanges2 = memoize(async (collateral: number | string, routeIdx: number):
|
|
1385
|
+
Promise<IDict<{ maxBorrowable: string, maxCollateral: string, leverage: string}>> => {
|
|
1386
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1387
|
+
|
|
1388
|
+
const calls = [];
|
|
1389
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1390
|
+
calls.push(llamalend.contracts[this.leverageZap].multicallContract.max_borrowable_and_collateral(_collateral, N, routeIdx));
|
|
1391
|
+
}
|
|
1392
|
+
const _res: bigint[][] = await llamalend.multicallProvider.all(calls);
|
|
1393
|
+
|
|
1394
|
+
const res: IDict<{ maxBorrowable: string, maxCollateral: string, leverage: string }> = {};
|
|
1395
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1396
|
+
const maxBorrowable = llamalend.formatUnits(_res[N - this.minBands][0] * BigInt(999) / BigInt(1000));
|
|
1397
|
+
const maxCollateral = llamalend.formatUnits(_res[N - this.minBands][1]* BigInt(999) / BigInt(1000), this.collateralDecimals);
|
|
1398
|
+
res[N] = {
|
|
1399
|
+
maxBorrowable,
|
|
1400
|
+
maxCollateral,
|
|
1401
|
+
leverage: BN(maxCollateral).div(collateral).toFixed(4),
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
return res;
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
promise: true,
|
|
1409
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
1410
|
+
});
|
|
1411
|
+
|
|
1412
|
+
private _leverageCreateLoanCollateral = memoize(async (userCollateral: number | string, debt: number | string):
|
|
1413
|
+
Promise<{ _collateral: bigint, routeIdx: number }> => {
|
|
1414
|
+
const _userCollateral = parseUnits(userCollateral, this.collateralDecimals);
|
|
1415
|
+
const _debt = parseUnits(debt);
|
|
1416
|
+
const calls = [];
|
|
1417
|
+
for (let i = 0; i < 5; i++) {
|
|
1418
|
+
calls.push(llamalend.contracts[this.leverageZap].multicallContract.get_collateral(_debt, i));
|
|
1419
|
+
}
|
|
1420
|
+
const _leverageCollateral: bigint[] = await llamalend.multicallProvider.all(calls);
|
|
1421
|
+
const routeIdx = this._getBestIdx(_leverageCollateral);
|
|
1422
|
+
|
|
1423
|
+
return { _collateral: _userCollateral + _leverageCollateral[routeIdx], routeIdx }
|
|
1424
|
+
},
|
|
1425
|
+
{
|
|
1426
|
+
promise: true,
|
|
1427
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
1428
|
+
});
|
|
1429
|
+
|
|
1430
|
+
private async _getRouteIdx(userCollateral: number | string, debt: number | string): Promise<number> {
|
|
1431
|
+
const { routeIdx } = await this._leverageCreateLoanCollateral(userCollateral, debt);
|
|
1432
|
+
|
|
1433
|
+
return routeIdx;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
private async leverageCreateLoanCollateral(userCollateral: number | string, debt: number | string):
|
|
1437
|
+
Promise<{ collateral: string, leverage: string, routeIdx: number }> {
|
|
1438
|
+
this._checkLeverageZap();
|
|
1439
|
+
const { _collateral, routeIdx } = await this._leverageCreateLoanCollateral(userCollateral, debt);
|
|
1440
|
+
const collateral = llamalend.formatUnits(_collateral, this.collateralDecimals);
|
|
1441
|
+
|
|
1442
|
+
return { collateral, leverage: BN(collateral).div(userCollateral).toFixed(4), routeIdx };
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
private async leverageGetRouteName(routeIdx: number): Promise<string> {
|
|
1446
|
+
this._checkLeverageZap();
|
|
1447
|
+
return await llamalend.contracts[this.leverageZap].contract.route_names(routeIdx);
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
private async leverageGetMaxRange(collateral: number | string, debt: number | string): Promise<number> {
|
|
1451
|
+
this._checkLeverageZap();
|
|
1452
|
+
const routeIdx = await this._getRouteIdx(collateral, debt);
|
|
1453
|
+
const maxRecv = await this._leverageCreateLoanMaxRecvAllRanges2(collateral, routeIdx);
|
|
1454
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1455
|
+
if (BN(debt).gt(BN(maxRecv[N].maxBorrowable))) return N - 1;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
return this.maxBands;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
private async _leverageCalcN1(collateral: number | string, debt: number | string, range: number): Promise<bigint> {
|
|
1462
|
+
this._checkRange(range);
|
|
1463
|
+
const routeIdx = await this._getRouteIdx(collateral, debt);
|
|
1464
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1465
|
+
const _debt = parseUnits(debt);
|
|
1466
|
+
return await llamalend.contracts[this.leverageZap].contract.calculate_debt_n1(_collateral, _debt, range, routeIdx, llamalend.constantOptions);
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
private async _leverageCalcN1AllRanges(collateral: number | string, debt: number | string, maxN: number): Promise<bigint[]> {
|
|
1470
|
+
const routeIdx = await this._getRouteIdx(collateral, debt);
|
|
1471
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1472
|
+
const _debt = parseUnits(debt);
|
|
1473
|
+
const calls = [];
|
|
1474
|
+
for (let N = this.minBands; N <= maxN; N++) {
|
|
1475
|
+
calls.push(llamalend.contracts[this.leverageZap].multicallContract.calculate_debt_n1(_collateral, _debt, N, routeIdx));
|
|
1476
|
+
}
|
|
1477
|
+
return await llamalend.multicallProvider.all(calls) as bigint[];
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
private async _leverageCreateLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[bigint, bigint]> {
|
|
1481
|
+
const _n1 = await this._leverageCalcN1(collateral, debt, range);
|
|
1482
|
+
const _n2 = _n1 + BigInt(range - 1);
|
|
1483
|
+
|
|
1484
|
+
return [_n2, _n1];
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
private async _leverageCreateLoanBandsAllRanges(collateral: number | string, debt: number | string): Promise<IDict<[bigint, bigint]>> {
|
|
1488
|
+
const maxN = await this.leverageGetMaxRange(collateral, debt);
|
|
1489
|
+
const _n1_arr = await this._leverageCalcN1AllRanges(collateral, debt, maxN);
|
|
1490
|
+
const _n2_arr: bigint[] = [];
|
|
1491
|
+
for (let N = this.minBands; N <= maxN; N++) {
|
|
1492
|
+
_n2_arr.push(_n1_arr[N - this.minBands] + BigInt(N - 1));
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
const _bands: IDict<[bigint, bigint]> = {};
|
|
1496
|
+
for (let N = this.minBands; N <= maxN; N++) {
|
|
1497
|
+
_bands[N] = [_n2_arr[N - this.minBands], _n1_arr[N - this.minBands]];
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
return _bands;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
private async leverageCreateLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[number, number]> {
|
|
1504
|
+
this._checkLeverageZap();
|
|
1505
|
+
const [_n2, _n1] = await this._leverageCreateLoanBands(collateral, debt, range);
|
|
1506
|
+
|
|
1507
|
+
return [Number(_n2), Number(_n1)];
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
private async leverageCreateLoanBandsAllRanges(collateral: number | string, debt: number | string): Promise<IDict<[number, number] | null>> {
|
|
1511
|
+
this._checkLeverageZap();
|
|
1512
|
+
const _bands = await this._leverageCreateLoanBandsAllRanges(collateral, debt);
|
|
1513
|
+
|
|
1514
|
+
const bands: { [index: number]: [number, number] | null } = {};
|
|
1515
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1516
|
+
if (_bands[N]) {
|
|
1517
|
+
bands[N] = _bands[N].map(Number) as [number, number];
|
|
1518
|
+
} else {
|
|
1519
|
+
bands[N] = null
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
return bands;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
private async leverageCreateLoanPrices(collateral: number | string, debt: number | string, range: number): Promise<string[]> {
|
|
1527
|
+
this._checkLeverageZap();
|
|
1528
|
+
const [_n2, _n1] = await this._leverageCreateLoanBands(collateral, debt, range);
|
|
1529
|
+
|
|
1530
|
+
return await this._getPrices(_n2, _n1);
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
private async leverageCreateLoanPricesAllRanges(collateral: number | string, debt: number | string): Promise<IDict<[string, string] | null>> {
|
|
1534
|
+
this._checkLeverageZap();
|
|
1535
|
+
const _bands = await this._leverageCreateLoanBandsAllRanges(collateral, debt);
|
|
1536
|
+
|
|
1537
|
+
const prices: { [index: number]: [string, string] | null } = {};
|
|
1538
|
+
for (let N = this.minBands; N <= this.maxBands; N++) {
|
|
1539
|
+
if (_bands[N]) {
|
|
1540
|
+
prices[N] = await this._calcPrices(..._bands[N]);
|
|
1541
|
+
} else {
|
|
1542
|
+
prices[N] = null
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
return prices;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
private async leverageCreateLoanHealth(collateral: number | string, debt: number | string, range: number, full = true): Promise<string> {
|
|
1550
|
+
this._checkLeverageZap();
|
|
1551
|
+
const address = "0x0000000000000000000000000000000000000000";
|
|
1552
|
+
const { _collateral } = await this._leverageCreateLoanCollateral(collateral, debt);
|
|
1553
|
+
const _debt = parseUnits(debt);
|
|
1554
|
+
|
|
1555
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
1556
|
+
let _health = await contract.health_calculator(address, _collateral, _debt, full, range, llamalend.constantOptions) as bigint;
|
|
1557
|
+
_health = _health * BigInt(100);
|
|
1558
|
+
|
|
1559
|
+
return formatUnits(_health);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
public async leveragePriceImpact(collateral: number | string, debt: number | string): Promise<string> {
|
|
1563
|
+
const x_BN = BN(debt);
|
|
1564
|
+
const small_x_BN = BN(100);
|
|
1565
|
+
const { _collateral, routeIdx } = await this._leverageCreateLoanCollateral(collateral, debt);
|
|
1566
|
+
const _y = _collateral - parseUnits(collateral, this.collateralDecimals);
|
|
1567
|
+
const _small_y = await llamalend.contracts[this.leverageZap].contract.get_collateral(fromBN(small_x_BN), routeIdx);
|
|
1568
|
+
const y_BN = toBN(_y, this.collateralDecimals);
|
|
1569
|
+
const small_y_BN = toBN(_small_y, this.collateralDecimals);
|
|
1570
|
+
const rateBN = y_BN.div(x_BN);
|
|
1571
|
+
const smallRateBN = small_y_BN.div(small_x_BN);
|
|
1572
|
+
if (rateBN.gt(smallRateBN)) return "0.0";
|
|
1573
|
+
|
|
1574
|
+
return BN(1).minus(rateBN.div(smallRateBN)).times(100).toFixed(4);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
private async _leverageCreateLoan(collateral: number | string, debt: number | string, range: number, slippage: number, estimateGas: boolean): Promise<string | TGas> {
|
|
1578
|
+
if (await this.loanExists()) throw Error("Loan already created");
|
|
1579
|
+
this._checkRange(range);
|
|
1580
|
+
|
|
1581
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1582
|
+
const _debt = parseUnits(debt);
|
|
1583
|
+
const leverageContract = llamalend.contracts[this.leverageZap].contract;
|
|
1584
|
+
const routeIdx = await this._getRouteIdx(collateral, debt);
|
|
1585
|
+
const _expected = await leverageContract.get_collateral_underlying(_debt, routeIdx, llamalend.constantOptions);
|
|
1586
|
+
const minRecvBN = toBN(_expected, this.collateralDecimals).times(100 - slippage).div(100);
|
|
1587
|
+
const _minRecv = fromBN(minRecvBN, this.collateralDecimals);
|
|
1588
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
1589
|
+
const value = isEth(this.collateral) ? _collateral : llamalend.parseUnits("0");
|
|
1590
|
+
const gas = await contract.create_loan_extended.estimateGas(
|
|
1591
|
+
_collateral,
|
|
1592
|
+
_debt,
|
|
1593
|
+
range,
|
|
1594
|
+
this.leverageZap,
|
|
1595
|
+
[routeIdx, _minRecv],
|
|
1596
|
+
{ ...llamalend.constantOptions, value }
|
|
1597
|
+
);
|
|
1598
|
+
if (estimateGas) return smartNumber(gas);
|
|
1599
|
+
|
|
1600
|
+
await llamalend.updateFeeData();
|
|
1601
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
1602
|
+
return (await contract.create_loan_extended(
|
|
1603
|
+
_collateral,
|
|
1604
|
+
_debt,
|
|
1605
|
+
range,
|
|
1606
|
+
this.leverageZap,
|
|
1607
|
+
[routeIdx, _minRecv],
|
|
1608
|
+
{ ...llamalend.options, gasLimit, value }
|
|
1609
|
+
)).hash
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
private async leverageCreateLoanEstimateGas(collateral: number | string, debt: number | string, range: number, slippage = 0.1): Promise<number> {
|
|
1613
|
+
this._checkLeverageZap();
|
|
1614
|
+
if (!(await this.createLoanIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
|
|
1615
|
+
return await this._leverageCreateLoan(collateral, debt, range, slippage, true) as number;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
private async leverageCreateLoan(collateral: number | string, debt: number | string, range: number, slippage = 0.1): Promise<string> {
|
|
1619
|
+
this._checkLeverageZap();
|
|
1620
|
+
await this.createLoanApprove(collateral);
|
|
1621
|
+
return await this._leverageCreateLoan(collateral, debt, range, slippage, false) as string;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// ---------------- DELEVERAGE REPAY ----------------
|
|
1625
|
+
|
|
1626
|
+
private _checkDeleverageZap(): void {
|
|
1627
|
+
if (this.deleverageZap === "0x0000000000000000000000000000000000000000") throw Error(`There is no deleverage for ${this.id} market`)
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
private deleverageRepayStablecoins = memoize( async (collateral: number | string): Promise<{ stablecoins: string, routeIdx: number }> => {
|
|
1631
|
+
this._checkDeleverageZap();
|
|
1632
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1633
|
+
const calls = [];
|
|
1634
|
+
for (let i = 0; i < 5; i++) {
|
|
1635
|
+
calls.push(llamalend.contracts[this.deleverageZap].multicallContract.get_stablecoins(_collateral, i));
|
|
1636
|
+
}
|
|
1637
|
+
const _stablecoins_arr: bigint[] = await llamalend.multicallProvider.all(calls);
|
|
1638
|
+
const routeIdx = this._getBestIdx(_stablecoins_arr);
|
|
1639
|
+
const stablecoins = llamalend.formatUnits(_stablecoins_arr[routeIdx]);
|
|
1640
|
+
|
|
1641
|
+
return { stablecoins, routeIdx };
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
promise: true,
|
|
1645
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
1646
|
+
});
|
|
1647
|
+
|
|
1648
|
+
private async deleverageGetRouteName(routeIdx: number): Promise<string> {
|
|
1649
|
+
this._checkDeleverageZap();
|
|
1650
|
+
return await llamalend.contracts[this.deleverageZap].contract.route_names(routeIdx);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
private async deleverageIsFullRepayment(deleverageCollateral: number | string, address = ""): Promise<boolean> {
|
|
1654
|
+
address = _getAddress(address);
|
|
1655
|
+
const { stablecoin, debt } = await this.userState(address);
|
|
1656
|
+
const { stablecoins: deleverageStablecoins } = await this.deleverageRepayStablecoins(deleverageCollateral);
|
|
1657
|
+
|
|
1658
|
+
return BN(stablecoin).plus(deleverageStablecoins).gt(debt);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
private async deleverageIsAvailable(deleverageCollateral: number | string, address = ""): Promise<boolean> {
|
|
1662
|
+
// 0. const { collateral, stablecoin, debt } = await this.userState(address);
|
|
1663
|
+
// 1. maxCollateral for deleverage is collateral from line above (0).
|
|
1664
|
+
// 2. If user is underwater (stablecoin > 0), only full repayment is available:
|
|
1665
|
+
// await this.deleverageRepayStablecoins(deleverageCollateral) + stablecoin > debt
|
|
1666
|
+
|
|
1667
|
+
// There is no deleverage zap
|
|
1668
|
+
if (this.deleverageZap === "0x0000000000000000000000000000000000000000") return false;
|
|
1669
|
+
|
|
1670
|
+
address = _getAddress(address);
|
|
1671
|
+
const { collateral, stablecoin, debt } = await this.userState(address);
|
|
1672
|
+
// Loan does not exist
|
|
1673
|
+
if (BN(debt).eq(0)) return false;
|
|
1674
|
+
// Can't spend more than user has
|
|
1675
|
+
if (BN(deleverageCollateral).gt(collateral)) return false;
|
|
1676
|
+
// Only full repayment and closing the position is available if user is underwater+
|
|
1677
|
+
if (BN(stablecoin).gt(0)) return await this.deleverageIsFullRepayment(deleverageCollateral, address);
|
|
1678
|
+
|
|
1679
|
+
return true;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
private _deleverageRepayBands = memoize( async (collateral: number | string, address: string): Promise<[bigint, bigint]> => {
|
|
1683
|
+
address = _getAddress(address);
|
|
1684
|
+
if (!(await this.deleverageIsAvailable(collateral, address))) return [parseUnits(0, 0), parseUnits(0, 0)];
|
|
1685
|
+
const { routeIdx } = await this.deleverageRepayStablecoins(collateral);
|
|
1686
|
+
const { _debt: _currentDebt } = await this._userState(address);
|
|
1687
|
+
if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
|
|
1688
|
+
|
|
1689
|
+
const N = await this.userRange(address);
|
|
1690
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1691
|
+
let _n1 = parseUnits(0, 0);
|
|
1692
|
+
let _n2 = parseUnits(0, 0);
|
|
1693
|
+
try {
|
|
1694
|
+
_n1 = await llamalend.contracts[this.deleverageZap].contract.calculate_debt_n1(_collateral, routeIdx, address);
|
|
1695
|
+
_n2 = _n1 + BigInt(N - 1);
|
|
1696
|
+
} catch (e) {
|
|
1697
|
+
console.log("Full repayment");
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
return [_n2, _n1];
|
|
1701
|
+
},
|
|
1702
|
+
{
|
|
1703
|
+
promise: true,
|
|
1704
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
private async deleverageRepayBands(collateral: number | string, address = ""): Promise<[number, number]> {
|
|
1708
|
+
this._checkDeleverageZap();
|
|
1709
|
+
const [_n2, _n1] = await this._deleverageRepayBands(collateral, address);
|
|
1710
|
+
|
|
1711
|
+
return [Number(_n2), Number(_n1)];
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
private async deleverageRepayPrices(debt: number | string, address = ""): Promise<string[]> {
|
|
1715
|
+
this._checkDeleverageZap();
|
|
1716
|
+
const [_n2, _n1] = await this._deleverageRepayBands(debt, address);
|
|
1717
|
+
|
|
1718
|
+
return await this._getPrices(_n2, _n1);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
private async deleverageRepayHealth(collateral: number | string, full = true, address = ""): Promise<string> {
|
|
1722
|
+
this._checkDeleverageZap();
|
|
1723
|
+
address = _getAddress(address);
|
|
1724
|
+
if (!(await this.deleverageIsAvailable(collateral, address))) return "0.0";
|
|
1725
|
+
const { _stablecoin, _debt } = await this._userState(address);
|
|
1726
|
+
const { stablecoins: deleverageStablecoins } = await this.deleverageRepayStablecoins(collateral);
|
|
1727
|
+
const _d_collateral = parseUnits(collateral, this.collateralDecimals) * BigInt(-1);
|
|
1728
|
+
const _d_debt = (parseUnits(deleverageStablecoins) + _stablecoin) * BigInt(-1);
|
|
1729
|
+
const N = await this.userRange(address);
|
|
1730
|
+
|
|
1731
|
+
if ((_debt + _d_debt) < 0) return "0.0";
|
|
1732
|
+
const contract = llamalend.contracts[this.healthCalculator ?? this.controller].contract;
|
|
1733
|
+
let _health = await contract.health_calculator(address, _d_collateral, _d_debt, full, N, llamalend.constantOptions) as bigint;
|
|
1734
|
+
_health = _health * BigInt(100);
|
|
1735
|
+
|
|
1736
|
+
return formatUnits(_health);
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
public async deleveragePriceImpact(collateral: number | string): Promise<string> {
|
|
1740
|
+
const x_BN = BN(collateral);
|
|
1741
|
+
const small_x_BN = BN(0.001);
|
|
1742
|
+
const { stablecoins, routeIdx } = await this.deleverageRepayStablecoins(collateral);
|
|
1743
|
+
const _y = parseUnits(stablecoins);
|
|
1744
|
+
const _small_y = await llamalend.contracts[this.deleverageZap].contract.get_stablecoins(fromBN(small_x_BN, this.collateralDecimals), routeIdx);
|
|
1745
|
+
const y_BN = toBN(_y);
|
|
1746
|
+
const small_y_BN = toBN(_small_y);
|
|
1747
|
+
const rateBN = y_BN.div(x_BN);
|
|
1748
|
+
const smallRateBN = small_y_BN.div(small_x_BN);
|
|
1749
|
+
if (rateBN.gt(smallRateBN)) return "0.0";
|
|
1750
|
+
|
|
1751
|
+
return BN(1).minus(rateBN.div(smallRateBN)).times(100).toFixed(4);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
private async _deleverageRepay(collateral: number | string, slippage: number, estimateGas: boolean): Promise<string | TGas> {
|
|
1755
|
+
const { debt: currentDebt } = await this.userState(llamalend.signerAddress);
|
|
1756
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${llamalend.signerAddress} does not exist`);
|
|
1757
|
+
|
|
1758
|
+
const { stablecoins, routeIdx } = await this.deleverageRepayStablecoins(collateral);
|
|
1759
|
+
const _collateral = parseUnits(collateral, this.collateralDecimals);
|
|
1760
|
+
const _debt = parseUnits(stablecoins);
|
|
1761
|
+
const minRecvBN = toBN(_debt).times(100 - slippage).div(100);
|
|
1762
|
+
const _minRecv = fromBN(minRecvBN);
|
|
1763
|
+
const contract = llamalend.contracts[this.controller].contract;
|
|
1764
|
+
const gas = await contract.repay_extended.estimateGas(this.deleverageZap, [routeIdx, _collateral, _minRecv], llamalend.constantOptions);
|
|
1765
|
+
if (estimateGas) return smartNumber(gas);
|
|
1766
|
+
|
|
1767
|
+
await llamalend.updateFeeData();
|
|
1768
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
1769
|
+
return (await contract.repay_extended(this.deleverageZap, [routeIdx, _collateral, _minRecv], { ...llamalend.options, gasLimit })).hash
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
private async deleverageRepayEstimateGas(collateral: number | string, slippage = 0.1): Promise<number> {
|
|
1773
|
+
this._checkDeleverageZap();
|
|
1774
|
+
return await this._deleverageRepay(collateral, slippage, true) as number;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
private async deleverageRepay(collateral: number | string, slippage = 0.1): Promise<string> {
|
|
1778
|
+
this._checkDeleverageZap();
|
|
1779
|
+
return await this._deleverageRepay(collateral, slippage, false) as string;
|
|
1780
|
+
}
|
|
1781
|
+
}
|