@curvefi/llamalend-api 1.0.23 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/lib/external-api.d.ts +1 -0
- package/lib/external-api.js +7 -0
- package/lib/interfaces.d.ts +5 -0
- package/lib/lendMarkets/LendMarketTemplate.d.ts +10 -1
- package/lib/lendMarkets/LendMarketTemplate.js +78 -0
- package/lib/llamalend.d.ts +1 -0
- package/lib/llamalend.js +9 -1
- package/package.json +1 -1
- package/src/external-api.ts +12 -0
- package/src/interfaces.ts +6 -0
- package/src/lendMarkets/LendMarketTemplate.ts +90 -2
- package/src/llamalend.ts +10 -1
package/README.md
CHANGED
|
@@ -807,6 +807,44 @@ import llamalend from "@curvefi/llamalend-api";
|
|
|
807
807
|
})()
|
|
808
808
|
```
|
|
809
809
|
|
|
810
|
+
### Partial self-liquidation for lendMarket
|
|
811
|
+
```ts
|
|
812
|
+
(async () => {
|
|
813
|
+
await llamalend.init('JsonRpc', {});
|
|
814
|
+
|
|
815
|
+
const lendMarket = llamalend.getLendMarket('one-way-market-0');
|
|
816
|
+
|
|
817
|
+
// Wallet balances: {
|
|
818
|
+
// borrowed: '301.533523886491869218',
|
|
819
|
+
// collateral: '0.860611976623971606'
|
|
820
|
+
// }
|
|
821
|
+
// State: {
|
|
822
|
+
// collateral: '0.139388023376028394',
|
|
823
|
+
// borrowed: '2751.493405530582315609',
|
|
824
|
+
// debt: '3053.026929417074184827'
|
|
825
|
+
// }
|
|
826
|
+
|
|
827
|
+
await lendMarket.tokensToLiquidate();
|
|
828
|
+
// 301.533523886491869218
|
|
829
|
+
|
|
830
|
+
const fraction = await lendMarket.calcPartialFrac(140); // <- 140 - amount (should be less then lendMarket.tokensToLiquidate)
|
|
831
|
+
// {frac: '472880873283878292', fracDecimal: '0.47288087328387829207', amount: 140}
|
|
832
|
+
//
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
await lendMarket.partialSelfLiquidateIsApproved(fraction);
|
|
836
|
+
// false
|
|
837
|
+
await lendMarket.partialSelfLiquidateApprove(fraction);
|
|
838
|
+
// []
|
|
839
|
+
await lendMarket.partialSelfLiquidateIsApproved(fraction);
|
|
840
|
+
// true
|
|
841
|
+
await lendMarket.partialSelfLiquidate(fraction, 0.1); // slippage = 0.1 %
|
|
842
|
+
|
|
843
|
+
// Wallet balances: { borrowed: '0', collateral: '0.7' }
|
|
844
|
+
// State: { collateral: '0.6', borrowed: '1300', debt: '1500' }
|
|
845
|
+
})()
|
|
846
|
+
```
|
|
847
|
+
|
|
810
848
|
### Liquidation for lendMarket
|
|
811
849
|
```ts
|
|
812
850
|
(async () => {
|
package/lib/external-api.d.ts
CHANGED
|
@@ -16,4 +16,5 @@ export declare const _getMarketsData: ((network: INetworkName) => Promise<IMarke
|
|
|
16
16
|
export declare function _getQuoteOdos(this: Llamalend, fromToken: string, toToken: string, _amount: bigint, blacklist: string, pathVizImage: boolean, slippage?: number): Promise<IQuoteOdos>;
|
|
17
17
|
export declare function _getExpectedOdos(this: Llamalend, fromToken: string, toToken: string, _amount: bigint, blacklist: string): Promise<string>;
|
|
18
18
|
export declare function _assembleTxOdos(this: Llamalend, pathId: string): Promise<string>;
|
|
19
|
+
export declare const _getHiddenPools: (() => Promise<any>) & memoize.Memoized<() => Promise<any>>;
|
|
19
20
|
export {};
|
package/lib/external-api.js
CHANGED
|
@@ -188,3 +188,10 @@ export function _assembleTxOdos(pathId) {
|
|
|
188
188
|
return _assembleTxOdosMemoized(this.constants.ALIASES.leverage_zap, pathId);
|
|
189
189
|
});
|
|
190
190
|
}
|
|
191
|
+
export const _getHiddenPools = memoize(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
192
|
+
const response = yield fetch(`https://api.curve.finance/api/getHiddenPools`);
|
|
193
|
+
return (yield response.json()).data;
|
|
194
|
+
}), {
|
|
195
|
+
promise: true,
|
|
196
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
197
|
+
});
|
package/lib/interfaces.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ export interface ICurveContract {
|
|
|
14
14
|
}
|
|
15
15
|
export type TAmount = number | string;
|
|
16
16
|
export type TGas = number | number[];
|
|
17
|
+
export interface IPartialFrac {
|
|
18
|
+
frac: string;
|
|
19
|
+
fracDecimal: string;
|
|
20
|
+
amount: string;
|
|
21
|
+
}
|
|
17
22
|
export interface ILlamma {
|
|
18
23
|
amm_address: string;
|
|
19
24
|
controller_address: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import memoize from "memoizee";
|
|
2
2
|
import type { Llamalend } from "../llamalend.js";
|
|
3
|
-
import { IDict, TGas, TAmount, IReward, IQuoteOdos, IOneWayMarket } from "../interfaces.js";
|
|
3
|
+
import { IDict, TGas, TAmount, IReward, IQuoteOdos, IOneWayMarket, IPartialFrac } from "../interfaces.js";
|
|
4
4
|
export declare class LendMarketTemplate {
|
|
5
5
|
private llamalend;
|
|
6
6
|
id: string;
|
|
@@ -50,6 +50,8 @@ export declare class LendMarketTemplate {
|
|
|
50
50
|
liquidate: (address: string, slippage?: number) => Promise<TGas>;
|
|
51
51
|
selfLiquidateApprove: () => Promise<TGas>;
|
|
52
52
|
selfLiquidate: (slippage?: number) => Promise<TGas>;
|
|
53
|
+
partialSelfLiquidateApprove: (partialFrac: IPartialFrac) => Promise<TGas>;
|
|
54
|
+
partialSelfLiquidate: (partialFrac: IPartialFrac, slippage?: number) => Promise<TGas>;
|
|
53
55
|
};
|
|
54
56
|
stats: {
|
|
55
57
|
parameters: () => Promise<{
|
|
@@ -441,10 +443,12 @@ export declare class LendMarketTemplate {
|
|
|
441
443
|
swapEstimateGas(i: number, j: number, amount: number | string, slippage?: number): Promise<TGas>;
|
|
442
444
|
swap(i: number, j: number, amount: number | string, slippage?: number): Promise<string>;
|
|
443
445
|
tokensToLiquidate(address?: string): Promise<string>;
|
|
446
|
+
calcPartialFrac(amount: TAmount, address?: string): Promise<IPartialFrac>;
|
|
444
447
|
liquidateIsApproved(address?: string): Promise<boolean>;
|
|
445
448
|
private liquidateApproveEstimateGas;
|
|
446
449
|
liquidateApprove(address?: string): Promise<string[]>;
|
|
447
450
|
private _liquidate;
|
|
451
|
+
private _partialLiquidate;
|
|
448
452
|
liquidateEstimateGas(address: string, slippage?: number): Promise<TGas>;
|
|
449
453
|
liquidate(address: string, slippage?: number): Promise<string>;
|
|
450
454
|
selfLiquidateIsApproved(): Promise<boolean>;
|
|
@@ -452,6 +456,11 @@ export declare class LendMarketTemplate {
|
|
|
452
456
|
selfLiquidateApprove(): Promise<string[]>;
|
|
453
457
|
selfLiquidateEstimateGas(slippage?: number): Promise<TGas>;
|
|
454
458
|
selfLiquidate(slippage?: number): Promise<string>;
|
|
459
|
+
partialSelfLiquidateIsApproved(partialFrac: IPartialFrac): Promise<boolean>;
|
|
460
|
+
private partialSelfLiquidateApproveEstimateGas;
|
|
461
|
+
partialSelfLiquidateApprove(partialFrac: IPartialFrac): Promise<string[]>;
|
|
462
|
+
partialSelfLiquidateEstimateGas(partialFrac: IPartialFrac, slippage?: number): Promise<TGas>;
|
|
463
|
+
partialSelfLiquidate(partialFrac: IPartialFrac, slippage?: number): Promise<string>;
|
|
455
464
|
private hasLeverage;
|
|
456
465
|
private _checkLeverageZap;
|
|
457
466
|
private _get_k_effective_BN;
|
|
@@ -508,6 +508,8 @@ export class LendMarketTemplate {
|
|
|
508
508
|
liquidate: this.liquidateEstimateGas.bind(this),
|
|
509
509
|
selfLiquidateApprove: this.selfLiquidateApproveEstimateGas.bind(this),
|
|
510
510
|
selfLiquidate: this.selfLiquidateEstimateGas.bind(this),
|
|
511
|
+
partialSelfLiquidateApprove: this.partialSelfLiquidateApproveEstimateGas.bind(this),
|
|
512
|
+
partialSelfLiquidate: this.partialSelfLiquidateEstimateGas.bind(this),
|
|
511
513
|
};
|
|
512
514
|
this.stats = {
|
|
513
515
|
parameters: this.statsParameters.bind(this),
|
|
@@ -2007,6 +2009,27 @@ export class LendMarketTemplate {
|
|
|
2007
2009
|
return formatUnits(_tokens, this.borrowed_token.decimals);
|
|
2008
2010
|
});
|
|
2009
2011
|
}
|
|
2012
|
+
calcPartialFrac(amount_1) {
|
|
2013
|
+
return __awaiter(this, arguments, void 0, function* (amount, address = "") {
|
|
2014
|
+
address = _getAddress.call(this.llamalend, address);
|
|
2015
|
+
const tokensToLiquidate = yield this.tokensToLiquidate(address);
|
|
2016
|
+
const amountBN = BN(amount);
|
|
2017
|
+
const tokensToLiquidateBN = BN(tokensToLiquidate);
|
|
2018
|
+
if (amountBN.gt(tokensToLiquidateBN))
|
|
2019
|
+
throw Error("Amount cannot be greater than total tokens to liquidate");
|
|
2020
|
+
if (amountBN.lte(0))
|
|
2021
|
+
throw Error("Amount must be greater than 0");
|
|
2022
|
+
// Calculate frac = amount / tokensToLiquidate * 10**18
|
|
2023
|
+
// 100% = 10**18
|
|
2024
|
+
const fracDecimalBN = amountBN.div(tokensToLiquidateBN);
|
|
2025
|
+
const frac = fromBN(fracDecimalBN);
|
|
2026
|
+
return {
|
|
2027
|
+
frac: frac.toString(),
|
|
2028
|
+
fracDecimal: fracDecimalBN.toString(),
|
|
2029
|
+
amount: amountBN.toString(),
|
|
2030
|
+
};
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2010
2033
|
liquidateIsApproved() {
|
|
2011
2034
|
return __awaiter(this, arguments, void 0, function* (address = "") {
|
|
2012
2035
|
const tokensToLiquidate = yield this.tokensToLiquidate(address);
|
|
@@ -2047,6 +2070,32 @@ export class LendMarketTemplate {
|
|
|
2047
2070
|
return (yield contract.liquidate(address, _minAmount, Object.assign(Object.assign({}, this.llamalend.options), { gasLimit }))).hash;
|
|
2048
2071
|
});
|
|
2049
2072
|
}
|
|
2073
|
+
_partialLiquidate(address, partialFrac, slippage, estimateGas) {
|
|
2074
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2075
|
+
const { borrowed, debt: currentDebt } = yield this.userState(address);
|
|
2076
|
+
if (slippage <= 0)
|
|
2077
|
+
throw Error("Slippage must be > 0");
|
|
2078
|
+
if (slippage > 100)
|
|
2079
|
+
throw Error("Slippage must be <= 100");
|
|
2080
|
+
if (Number(currentDebt) === 0)
|
|
2081
|
+
throw Error(`Loan for ${address} does not exist`);
|
|
2082
|
+
if (Number(borrowed) === 0)
|
|
2083
|
+
throw Error(`User ${address} is not in liquidation mode`);
|
|
2084
|
+
const frac = partialFrac.frac;
|
|
2085
|
+
const fracBN = BN(partialFrac.fracDecimal);
|
|
2086
|
+
const borrowedBN = BN(borrowed);
|
|
2087
|
+
const expectedBorrowedBN = borrowedBN.times(fracBN);
|
|
2088
|
+
const minAmountBN = expectedBorrowedBN.times(100 - slippage).div(100);
|
|
2089
|
+
const _minAmount = fromBN(minAmountBN);
|
|
2090
|
+
const contract = this.llamalend.contracts[this.addresses.controller].contract;
|
|
2091
|
+
const gas = (yield contract.liquidate_extended.estimateGas(address, _minAmount, frac, this.llamalend.constants.ZERO_ADDRESS, [], this.llamalend.constantOptions));
|
|
2092
|
+
if (estimateGas)
|
|
2093
|
+
return smartNumber(gas);
|
|
2094
|
+
yield this.llamalend.updateFeeData();
|
|
2095
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
2096
|
+
return (yield contract.liquidate_extended(address, _minAmount, frac, this.llamalend.constants.ZERO_ADDRESS, [], Object.assign(Object.assign({}, this.llamalend.options), { gasLimit }))).hash;
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2050
2099
|
liquidateEstimateGas(address_1) {
|
|
2051
2100
|
return __awaiter(this, arguments, void 0, function* (address, slippage = 0.1) {
|
|
2052
2101
|
if (!(yield this.liquidateIsApproved(address)))
|
|
@@ -2089,6 +2138,35 @@ export class LendMarketTemplate {
|
|
|
2089
2138
|
return yield this._liquidate(this.llamalend.signerAddress, slippage, false);
|
|
2090
2139
|
});
|
|
2091
2140
|
}
|
|
2141
|
+
// ---------------- PARTIAL SELF-LIQUIDATE ----------------
|
|
2142
|
+
partialSelfLiquidateIsApproved(partialFrac) {
|
|
2143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2144
|
+
return yield hasAllowance.call(this.llamalend, [this.addresses.borrowed_token], [partialFrac.amount], this.llamalend.signerAddress, this.addresses.controller);
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
partialSelfLiquidateApproveEstimateGas(partialFrac) {
|
|
2148
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2149
|
+
return yield ensureAllowanceEstimateGas.call(this.llamalend, [this.addresses.borrowed_token], [partialFrac.amount], this.addresses.controller);
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
partialSelfLiquidateApprove(partialFrac) {
|
|
2153
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2154
|
+
return yield ensureAllowance.call(this.llamalend, [this.addresses.borrowed_token], [partialFrac.amount], this.addresses.controller);
|
|
2155
|
+
});
|
|
2156
|
+
}
|
|
2157
|
+
partialSelfLiquidateEstimateGas(partialFrac_1) {
|
|
2158
|
+
return __awaiter(this, arguments, void 0, function* (partialFrac, slippage = 0.1) {
|
|
2159
|
+
if (!(yield this.partialSelfLiquidateIsApproved(partialFrac)))
|
|
2160
|
+
throw Error("Approval is needed for gas estimation");
|
|
2161
|
+
return yield this._partialLiquidate(this.llamalend.signerAddress, partialFrac, slippage, true);
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
partialSelfLiquidate(partialFrac_1) {
|
|
2165
|
+
return __awaiter(this, arguments, void 0, function* (partialFrac, slippage = 0.1) {
|
|
2166
|
+
yield this.partialSelfLiquidateApprove(partialFrac);
|
|
2167
|
+
return yield this._partialLiquidate(this.llamalend.signerAddress, partialFrac, slippage, false);
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
2092
2170
|
_checkLeverageZap() {
|
|
2093
2171
|
if (!this.hasLeverage()) {
|
|
2094
2172
|
throw Error("This market does not support leverage");
|
package/lib/llamalend.d.ts
CHANGED
|
@@ -64,6 +64,7 @@ declare class Llamalend implements ILlamalend {
|
|
|
64
64
|
maxFeePerGas?: number;
|
|
65
65
|
maxPriorityFeePerGas?: number;
|
|
66
66
|
}): void;
|
|
67
|
+
_filterHiddenMarkets(markets: IDict<IOneWayMarket>): Promise<IDict<IOneWayMarket>>;
|
|
67
68
|
getLendMarketList: () => string[];
|
|
68
69
|
getMintMarketList: () => string[];
|
|
69
70
|
getFactoryMarketData: () => Promise<Record<string, any>>;
|
package/lib/llamalend.js
CHANGED
|
@@ -42,7 +42,7 @@ import { LLAMMAS } from "./constants/llammas";
|
|
|
42
42
|
import { L2Networks } from "./constants/L2Networks.js";
|
|
43
43
|
import { createCall, handleMultiCallResponse } from "./utils.js";
|
|
44
44
|
import { cacheKey, cacheStats } from "./cache/index.js";
|
|
45
|
-
import { _getMarketsData } from "./external-api.js";
|
|
45
|
+
import { _getMarketsData, _getHiddenPools } from "./external-api.js";
|
|
46
46
|
import { extractDecimals } from "./constants/utils.js";
|
|
47
47
|
export const NETWORK_CONSTANTS = {
|
|
48
48
|
1: {
|
|
@@ -296,6 +296,7 @@ class Llamalend {
|
|
|
296
296
|
collateral_token: COIN_DATA[collateral_tokens[index]],
|
|
297
297
|
};
|
|
298
298
|
});
|
|
299
|
+
this.constants.ONE_WAY_MARKETS = yield this._filterHiddenMarkets(this.constants.ONE_WAY_MARKETS);
|
|
299
300
|
yield this.fetchStats(amms, controllers, vaults, borrowed_tokens, collateral_tokens);
|
|
300
301
|
});
|
|
301
302
|
this._fetchOneWayMarketsByAPI = () => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -341,6 +342,7 @@ class Llamalend {
|
|
|
341
342
|
collateral_token: COIN_DATA[collateral_tokens[index]],
|
|
342
343
|
};
|
|
343
344
|
});
|
|
345
|
+
this.constants.ONE_WAY_MARKETS = yield this._filterHiddenMarkets(this.constants.ONE_WAY_MARKETS);
|
|
344
346
|
});
|
|
345
347
|
this.address = '00000';
|
|
346
348
|
this.crvUsdAddress = COINS_ETHEREUM.crvusd;
|
|
@@ -649,6 +651,12 @@ class Llamalend {
|
|
|
649
651
|
setCustomFeeData(customFeeData) {
|
|
650
652
|
this.feeData = Object.assign(Object.assign({}, this.feeData), customFeeData);
|
|
651
653
|
}
|
|
654
|
+
_filterHiddenMarkets(markets) {
|
|
655
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
656
|
+
const hiddenMarkets = (yield _getHiddenPools())[this.constants.NETWORK_NAME] || [];
|
|
657
|
+
return Object.fromEntries(Object.entries(markets).filter(([id]) => !hiddenMarkets.includes(id)));
|
|
658
|
+
});
|
|
659
|
+
}
|
|
652
660
|
formatUnits(value, unit) {
|
|
653
661
|
return ethers.formatUnits(value, unit);
|
|
654
662
|
}
|
package/package.json
CHANGED
package/src/external-api.ts
CHANGED
|
@@ -209,3 +209,15 @@ const _assembleTxOdosMemoized = memoize(
|
|
|
209
209
|
export async function _assembleTxOdos(this: Llamalend, pathId: string): Promise<string> {
|
|
210
210
|
return _assembleTxOdosMemoized(this.constants.ALIASES.leverage_zap, pathId);
|
|
211
211
|
}
|
|
212
|
+
|
|
213
|
+
export const _getHiddenPools = memoize(
|
|
214
|
+
async () => {
|
|
215
|
+
const response = await fetch(`https://api.curve.finance/api/getHiddenPools`)
|
|
216
|
+
|
|
217
|
+
return (await response.json() as any).data
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
promise: true,
|
|
221
|
+
maxAge: 5 * 60 * 1000, // 5m
|
|
222
|
+
}
|
|
223
|
+
)
|
package/src/interfaces.ts
CHANGED
|
@@ -18,6 +18,12 @@ export interface ICurveContract {
|
|
|
18
18
|
export type TAmount = number | string
|
|
19
19
|
export type TGas = number | number[]
|
|
20
20
|
|
|
21
|
+
export interface IPartialFrac {
|
|
22
|
+
frac: string;
|
|
23
|
+
fracDecimal: string;
|
|
24
|
+
amount: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
export interface ILlamma {
|
|
22
28
|
amm_address: string,
|
|
23
29
|
controller_address: string,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
DIGas,
|
|
23
23
|
smartNumber,
|
|
24
24
|
} from "../utils.js";
|
|
25
|
-
import {IDict, TGas, TAmount, IReward, IQuoteOdos, IOneWayMarket} from "../interfaces.js";
|
|
25
|
+
import {IDict, TGas, TAmount, IReward, IQuoteOdos, IOneWayMarket, IPartialFrac} from "../interfaces.js";
|
|
26
26
|
import { _getExpectedOdos, _getQuoteOdos, _assembleTxOdos, _getUserCollateral, _getMarketsData } from "../external-api.js";
|
|
27
27
|
import ERC20Abi from '../constants/abis/ERC20.json' with {type: 'json'};
|
|
28
28
|
import {cacheKey, cacheStats} from "../cache/index.js";
|
|
@@ -82,6 +82,8 @@ export class LendMarketTemplate {
|
|
|
82
82
|
liquidate: (address: string, slippage?: number) => Promise<TGas>,
|
|
83
83
|
selfLiquidateApprove: () => Promise<TGas>,
|
|
84
84
|
selfLiquidate: (slippage?: number) => Promise<TGas>,
|
|
85
|
+
partialSelfLiquidateApprove: (partialFrac: IPartialFrac) => Promise<TGas>,
|
|
86
|
+
partialSelfLiquidate: (partialFrac: IPartialFrac, slippage?: number) => Promise<TGas>,
|
|
85
87
|
};
|
|
86
88
|
stats: {
|
|
87
89
|
parameters: () => Promise<{
|
|
@@ -265,6 +267,8 @@ export class LendMarketTemplate {
|
|
|
265
267
|
liquidate: this.liquidateEstimateGas.bind(this),
|
|
266
268
|
selfLiquidateApprove: this.selfLiquidateApproveEstimateGas.bind(this),
|
|
267
269
|
selfLiquidate: this.selfLiquidateEstimateGas.bind(this),
|
|
270
|
+
partialSelfLiquidateApprove: this.partialSelfLiquidateApproveEstimateGas.bind(this),
|
|
271
|
+
partialSelfLiquidate: this.partialSelfLiquidateEstimateGas.bind(this),
|
|
268
272
|
}
|
|
269
273
|
this.stats = {
|
|
270
274
|
parameters: this.statsParameters.bind(this),
|
|
@@ -2043,10 +2047,31 @@ export class LendMarketTemplate {
|
|
|
2043
2047
|
public async tokensToLiquidate(address = ""): Promise<string> {
|
|
2044
2048
|
address = _getAddress.call(this.llamalend, address);
|
|
2045
2049
|
const _tokens = await this.llamalend.contracts[this.addresses.controller].contract.tokens_to_liquidate(address, this.llamalend.constantOptions) as bigint;
|
|
2046
|
-
|
|
2047
2050
|
return formatUnits(_tokens, this.borrowed_token.decimals)
|
|
2048
2051
|
}
|
|
2049
2052
|
|
|
2053
|
+
public async calcPartialFrac(amount: TAmount, address = ""): Promise<IPartialFrac> {
|
|
2054
|
+
address = _getAddress.call(this.llamalend, address);
|
|
2055
|
+
const tokensToLiquidate = await this.tokensToLiquidate(address);
|
|
2056
|
+
|
|
2057
|
+
const amountBN = BN(amount);
|
|
2058
|
+
const tokensToLiquidateBN = BN(tokensToLiquidate);
|
|
2059
|
+
|
|
2060
|
+
if (amountBN.gt(tokensToLiquidateBN)) throw Error("Amount cannot be greater than total tokens to liquidate");
|
|
2061
|
+
if (amountBN.lte(0)) throw Error("Amount must be greater than 0");
|
|
2062
|
+
|
|
2063
|
+
// Calculate frac = amount / tokensToLiquidate * 10**18
|
|
2064
|
+
// 100% = 10**18
|
|
2065
|
+
const fracDecimalBN = amountBN.div(tokensToLiquidateBN);
|
|
2066
|
+
const frac = fromBN(fracDecimalBN);
|
|
2067
|
+
return {
|
|
2068
|
+
frac: frac.toString(),
|
|
2069
|
+
fracDecimal: fracDecimalBN.toString(),
|
|
2070
|
+
amount: amountBN.toString(),
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
|
|
2050
2075
|
public async liquidateIsApproved(address = ""): Promise<boolean> {
|
|
2051
2076
|
const tokensToLiquidate = await this.tokensToLiquidate(address);
|
|
2052
2077
|
return await hasAllowance.call(this.llamalend, [this.addresses.borrowed_token], [tokensToLiquidate], this.llamalend.signerAddress, this.addresses.controller);
|
|
@@ -2080,6 +2105,45 @@ export class LendMarketTemplate {
|
|
|
2080
2105
|
return (await contract.liquidate(address, _minAmount, { ...this.llamalend.options, gasLimit })).hash
|
|
2081
2106
|
}
|
|
2082
2107
|
|
|
2108
|
+
private async _partialLiquidate(address: string, partialFrac: IPartialFrac, slippage: number, estimateGas: boolean): Promise<string | TGas> {
|
|
2109
|
+
const { borrowed, debt: currentDebt } = await this.userState(address);
|
|
2110
|
+
if (slippage <= 0) throw Error("Slippage must be > 0");
|
|
2111
|
+
if (slippage > 100) throw Error("Slippage must be <= 100");
|
|
2112
|
+
if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
|
|
2113
|
+
if (Number(borrowed) === 0) throw Error(`User ${address} is not in liquidation mode`);
|
|
2114
|
+
|
|
2115
|
+
const frac = partialFrac.frac;
|
|
2116
|
+
const fracBN = BN(partialFrac.fracDecimal);
|
|
2117
|
+
|
|
2118
|
+
const borrowedBN = BN(borrowed);
|
|
2119
|
+
const expectedBorrowedBN = borrowedBN.times(fracBN);
|
|
2120
|
+
const minAmountBN = expectedBorrowedBN.times(100 - slippage).div(100);
|
|
2121
|
+
const _minAmount = fromBN(minAmountBN);
|
|
2122
|
+
|
|
2123
|
+
const contract = this.llamalend.contracts[this.addresses.controller].contract;
|
|
2124
|
+
const gas = (await contract.liquidate_extended.estimateGas(
|
|
2125
|
+
address,
|
|
2126
|
+
_minAmount,
|
|
2127
|
+
frac,
|
|
2128
|
+
this.llamalend.constants.ZERO_ADDRESS,
|
|
2129
|
+
[],
|
|
2130
|
+
this.llamalend.constantOptions
|
|
2131
|
+
));
|
|
2132
|
+
|
|
2133
|
+
if (estimateGas) return smartNumber(gas);
|
|
2134
|
+
|
|
2135
|
+
await this.llamalend.updateFeeData();
|
|
2136
|
+
const gasLimit = _mulBy1_3(DIGas(gas));
|
|
2137
|
+
return (await contract.liquidate_extended(
|
|
2138
|
+
address,
|
|
2139
|
+
_minAmount,
|
|
2140
|
+
frac,
|
|
2141
|
+
this.llamalend.constants.ZERO_ADDRESS,
|
|
2142
|
+
[],
|
|
2143
|
+
{ ...this.llamalend.options, gasLimit }
|
|
2144
|
+
)).hash;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2083
2147
|
public async liquidateEstimateGas(address: string, slippage = 0.1): Promise<TGas> {
|
|
2084
2148
|
if (!(await this.liquidateIsApproved(address))) throw Error("Approval is needed for gas estimation");
|
|
2085
2149
|
return await this._liquidate(address, slippage, true) as TGas;
|
|
@@ -2114,6 +2178,30 @@ export class LendMarketTemplate {
|
|
|
2114
2178
|
return await this._liquidate(this.llamalend.signerAddress, slippage, false) as string;
|
|
2115
2179
|
}
|
|
2116
2180
|
|
|
2181
|
+
// ---------------- PARTIAL SELF-LIQUIDATE ----------------
|
|
2182
|
+
|
|
2183
|
+
public async partialSelfLiquidateIsApproved(partialFrac: IPartialFrac): Promise<boolean> {
|
|
2184
|
+
return await hasAllowance.call(this.llamalend, [this.addresses.borrowed_token], [partialFrac.amount], this.llamalend.signerAddress, this.addresses.controller);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
private async partialSelfLiquidateApproveEstimateGas(partialFrac: IPartialFrac): Promise<TGas> {
|
|
2188
|
+
return await ensureAllowanceEstimateGas.call(this.llamalend, [this.addresses.borrowed_token], [partialFrac.amount], this.addresses.controller);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
public async partialSelfLiquidateApprove(partialFrac: IPartialFrac): Promise<string[]> {
|
|
2192
|
+
return await ensureAllowance.call(this.llamalend, [this.addresses.borrowed_token], [partialFrac.amount], this.addresses.controller);
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
public async partialSelfLiquidateEstimateGas(partialFrac: IPartialFrac, slippage = 0.1): Promise<TGas> {
|
|
2196
|
+
if (!(await this.partialSelfLiquidateIsApproved(partialFrac))) throw Error("Approval is needed for gas estimation");
|
|
2197
|
+
return await this._partialLiquidate(this.llamalend.signerAddress, partialFrac, slippage, true) as TGas;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
public async partialSelfLiquidate(partialFrac: IPartialFrac, slippage = 0.1): Promise<string> {
|
|
2201
|
+
await this.partialSelfLiquidateApprove(partialFrac);
|
|
2202
|
+
return await this._partialLiquidate(this.llamalend.signerAddress, partialFrac, slippage, false) as string;
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2117
2205
|
// ---------------- LEVERAGE CREATE LOAN ----------------
|
|
2118
2206
|
|
|
2119
2207
|
private hasLeverage = (): boolean => {
|
package/src/llamalend.ts
CHANGED
|
@@ -79,7 +79,7 @@ import {LLAMMAS} from "./constants/llammas";
|
|
|
79
79
|
import {L2Networks} from "./constants/L2Networks.js";
|
|
80
80
|
import {createCall, handleMultiCallResponse} from "./utils.js";
|
|
81
81
|
import {cacheKey, cacheStats} from "./cache/index.js";
|
|
82
|
-
import {_getMarketsData} from "./external-api.js";
|
|
82
|
+
import {_getMarketsData, _getHiddenPools} from "./external-api.js";
|
|
83
83
|
import {extractDecimals} from "./constants/utils.js";
|
|
84
84
|
|
|
85
85
|
export const NETWORK_CONSTANTS: { [index: number]: any } = {
|
|
@@ -529,6 +529,11 @@ class Llamalend implements ILlamalend {
|
|
|
529
529
|
this.feeData = { ...this.feeData, ...customFeeData };
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
async _filterHiddenMarkets(markets: IDict<IOneWayMarket>): Promise<IDict<IOneWayMarket>> {
|
|
533
|
+
const hiddenMarkets = (await _getHiddenPools() as any)[this.constants.NETWORK_NAME] || [];
|
|
534
|
+
return Object.fromEntries(Object.entries(markets).filter(([id]) => !hiddenMarkets.includes(id))) as IDict<IOneWayMarket>;
|
|
535
|
+
}
|
|
536
|
+
|
|
532
537
|
getLendMarketList = () => Object.keys(this.constants.ONE_WAY_MARKETS);
|
|
533
538
|
|
|
534
539
|
getMintMarketList = () => Object.keys(this.constants.LLAMMAS);
|
|
@@ -720,6 +725,8 @@ class Llamalend implements ILlamalend {
|
|
|
720
725
|
}
|
|
721
726
|
})
|
|
722
727
|
|
|
728
|
+
this.constants.ONE_WAY_MARKETS = await this._filterHiddenMarkets(this.constants.ONE_WAY_MARKETS);
|
|
729
|
+
|
|
723
730
|
await this.fetchStats(amms, controllers, vaults, borrowed_tokens, collateral_tokens);
|
|
724
731
|
}
|
|
725
732
|
|
|
@@ -767,6 +774,8 @@ class Llamalend implements ILlamalend {
|
|
|
767
774
|
collateral_token: COIN_DATA[collateral_tokens[index]],
|
|
768
775
|
}
|
|
769
776
|
})
|
|
777
|
+
|
|
778
|
+
this.constants.ONE_WAY_MARKETS = await this._filterHiddenMarkets(this.constants.ONE_WAY_MARKETS);
|
|
770
779
|
}
|
|
771
780
|
|
|
772
781
|
formatUnits(value: BigNumberish, unit?: string | Numeric): string {
|