@gearbox-protocol/sdk 17.13.0-next.7 → 17.13.0-next.9
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/dist/cjs/onchain/accounts/liquidations/LiquidationsService.js +42 -25
- package/dist/cjs/sdk/rewards/merkl-api.js +1 -1
- package/dist/cjs/sdk/rewards/turtle-api.js +1 -1
- package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +42 -25
- package/dist/esm/sdk/rewards/merkl-api.js +1 -1
- package/dist/esm/sdk/rewards/turtle-api.js +1 -1
- package/dist/types/model/liquidations.d.ts +3 -4
- package/dist/types/onchain/accounts/liquidations/LiquidationsService.d.ts +9 -10
- package/dist/types/onchain/accounts/liquidations/types.d.ts +10 -33
- package/package.json +1 -1
|
@@ -23,6 +23,7 @@ require("../../market/index.js");
|
|
|
23
23
|
const require_onchain_accounts_liquidations_constants = require("./constants.js");
|
|
24
24
|
const require_onchain_accounts_liquidations_partialLiquidation = require("./partialLiquidation.js");
|
|
25
25
|
const require_onchain_accounts_liquidations_skipLiquidatableAccount = require("./skipLiquidatableAccount.js");
|
|
26
|
+
let viem = require("viem");
|
|
26
27
|
//#region src/onchain/accounts/liquidations/LiquidationsService.ts
|
|
27
28
|
/**
|
|
28
29
|
* Service for discovering liquidatable credit accounts and previewing manual
|
|
@@ -121,14 +122,15 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
121
122
|
* full one: what the liquidator pays, what it receives and what it must
|
|
122
123
|
* approve, plus {@link LiquidationDetails.isPartiallyLiquidatable}.
|
|
123
124
|
*
|
|
124
|
-
* A local estimate
|
|
125
|
-
*
|
|
125
|
+
* A local estimate, not onchain read: no price feed updates are applied, so
|
|
126
|
+
* `ignoreReservePrices` has no effect here.
|
|
127
|
+
* Parameters left out of `props` are derived from current state.
|
|
126
128
|
*
|
|
127
|
-
* @throws For
|
|
128
|
-
* `tokenOut` can be picked.
|
|
129
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), for a
|
|
130
|
+
* `tokenOut` that cannot be seized, and when no `tokenOut` can be picked.
|
|
129
131
|
**/
|
|
130
132
|
async getPartialLiquidationDetails(props) {
|
|
131
|
-
const { creditAccount, blockNumber } = props;
|
|
133
|
+
const { creditAccount, liquidator, blockNumber } = props;
|
|
132
134
|
const ca = await this.#getCreditAccountData(creditAccount, blockNumber);
|
|
133
135
|
const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
134
136
|
const { priceOracle } = suite.market;
|
|
@@ -137,6 +139,13 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
137
139
|
const { liquidationDiscount } = suite.liquidationFees();
|
|
138
140
|
const seizedValue = repaidAmount * require_onchain_constants_math.PERCENTAGE_FACTOR / BigInt(liquidationDiscount);
|
|
139
141
|
const seizedAmount = priceOracle.convert(underlying, tokenOut, repaidAmount) * require_onchain_constants_math.PERCENTAGE_FACTOR / BigInt(liquidationDiscount);
|
|
142
|
+
const nft = await suite.degenNFT();
|
|
143
|
+
let isLiquidatorEligible = !nft;
|
|
144
|
+
if (nft && liquidator) {
|
|
145
|
+
const requirements = await nft.getOpenAccountRequirements(liquidator, { tokenOutAddress: tokenOut });
|
|
146
|
+
isLiquidatorEligible = nft.isRegistered(requirements);
|
|
147
|
+
}
|
|
148
|
+
const [kycToken] = nft && !isLiquidatorEligible ? await nft.getTokens() : [];
|
|
140
149
|
return {
|
|
141
150
|
...this.#buildAccount(ca, suite),
|
|
142
151
|
repaymentAmount: priceOracle.toTokenAmount(underlying, repaidAmount),
|
|
@@ -147,7 +156,9 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
147
156
|
...priceOracle.toTokenAmount(tokenOut, seizedAmount),
|
|
148
157
|
token: this.sdk.tokensMeta.mustGetToken(this.sdk.tokensMeta.depositedToken(tokenOut))
|
|
149
158
|
}],
|
|
150
|
-
isLiquidatorEligible
|
|
159
|
+
isLiquidatorEligible,
|
|
160
|
+
kycProtocol: isLiquidatorEligible ? void 0 : nft?.protocol,
|
|
161
|
+
kycToken: kycToken ? this.sdk.tokensMeta.getToken(kycToken) : void 0,
|
|
151
162
|
isCreditAccountFrozen: false,
|
|
152
163
|
approve: repaidAmount === 0n ? void 0 : {
|
|
153
164
|
spender: suite.creditManager.address,
|
|
@@ -163,17 +174,18 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
163
174
|
* discounted collateral sent to the liquidator. Parameters left out of
|
|
164
175
|
* `props` are derived from current state.
|
|
165
176
|
*
|
|
166
|
-
* @throws For
|
|
167
|
-
* `tokenOut`
|
|
168
|
-
* liquidated, see
|
|
177
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), for a
|
|
178
|
+
* `tokenOut` that cannot be seized, when no `tokenOut` can be picked, and
|
|
179
|
+
* when the account cannot be partially liquidated, see
|
|
180
|
+
* {@link LiquidationDetails.isPartiallyLiquidatable}.
|
|
169
181
|
**/
|
|
170
182
|
async buildPartialLiquidationTx(props) {
|
|
171
|
-
const { creditAccount, liquidator, blockNumber } = props;
|
|
183
|
+
const { creditAccount, liquidator, ignoreReservePrices, blockNumber } = props;
|
|
172
184
|
const ca = await this.#getCreditAccountData(creditAccount, blockNumber);
|
|
173
185
|
const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
174
186
|
const params = this.#getPartialLiquidationParams(ca, suite, props);
|
|
175
187
|
if (!params.isPartiallyLiquidatable) throw new Error(`credit account ${this.labelAddress(creditAccount)} cannot be partially liquidated`);
|
|
176
|
-
const updates = await this.sdk.accounts.getOnDemandPriceUpdates(ca,
|
|
188
|
+
const updates = await this.sdk.accounts.getOnDemandPriceUpdates(ca, ignoreReservePrices);
|
|
177
189
|
const tx = suite.creditFacade.partiallyLiquidateCreditAccount(ca.creditAccount, params.tokenOut, params.repaidAmount, params.minSeizedAmount, liquidator, updates);
|
|
178
190
|
this.logger?.debug(`built tx to partially liquidate credit account ${this.labelAddress(creditAccount)} to ${this.labelAddress(liquidator)}`);
|
|
179
191
|
return {
|
|
@@ -185,9 +197,6 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
185
197
|
* Optimal partial liquidation of a credit account: the collateral to seize
|
|
186
198
|
* and the amounts that bring its health factor close to `optimalHF`.
|
|
187
199
|
*
|
|
188
|
-
* Prices come from the last synced oracle state and `ca`, not from fresh
|
|
189
|
-
* price updates. Withdrawal phantom tokens are never seized.
|
|
190
|
-
*
|
|
191
200
|
* @param ca - Credit account to partially liquidate.
|
|
192
201
|
* @param optimalHF - Health factor to aim for, in basis points. Defaults to
|
|
193
202
|
* {@link CreditSuite.optimalHFForPartialLiquidation}.
|
|
@@ -196,11 +205,12 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
196
205
|
* @throws If no `tokenOut` can be picked.
|
|
197
206
|
**/
|
|
198
207
|
getOptimalPartialLiquidation(ca, optimalHF, liquidationThresholds) {
|
|
208
|
+
const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
199
209
|
return require_onchain_accounts_liquidations_partialLiquidation.optimalPartialLiquidation({
|
|
200
|
-
suite
|
|
210
|
+
suite,
|
|
201
211
|
account: ca,
|
|
202
212
|
optimalHF,
|
|
203
|
-
exclude: (token) => this.#
|
|
213
|
+
exclude: (token) => this.#isUnseizable(suite, token),
|
|
204
214
|
liquidationThresholds
|
|
205
215
|
});
|
|
206
216
|
}
|
|
@@ -336,24 +346,32 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
336
346
|
/**
|
|
337
347
|
* Everything a partial liquidation of a credit account needs, with any
|
|
338
348
|
* parameter the caller pinned down taken as given and the rest derived from
|
|
339
|
-
* current state. A derived `tokenOut` is never a
|
|
349
|
+
* current state. A derived `tokenOut` is never a token that cannot be seized.
|
|
340
350
|
*
|
|
341
|
-
* @throws For
|
|
342
|
-
* the
|
|
343
|
-
* which does not redeem instantly,
|
|
344
|
-
*
|
|
351
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), whose
|
|
352
|
+
* repayment the liquidator cannot fund, for a `tokenOut` that cannot be
|
|
353
|
+
* seized (a withdrawal phantom token, which does not redeem instantly, or a
|
|
354
|
+
* phantom token that unwraps to the underlying), if a derived `tokenOut`
|
|
355
|
+
* cannot be picked, and if the seized token is not a collateral token of the
|
|
356
|
+
* credit manager.
|
|
345
357
|
**/
|
|
346
358
|
#getPartialLiquidationParams(ca, suite, overrides) {
|
|
347
359
|
const label = this.labelAddress(ca.creditAccount);
|
|
348
|
-
if (suite.
|
|
349
|
-
if (overrides.tokenOut && this.#
|
|
360
|
+
if (this.sdk.tokensMeta.isRWAUnderlying(this.sdk.tokensMeta.mustGet(suite.underlying))) throw new Error(`cannot partially liquidate ${label}: markets with a wrapped RWA underlying are not supported`);
|
|
361
|
+
if (overrides.tokenOut && this.#isUnseizable(suite, overrides.tokenOut)) throw new Error(`cannot partially liquidate ${label}: ${this.labelAddress(overrides.tokenOut)} cannot be seized`);
|
|
350
362
|
return require_onchain_accounts_liquidations_partialLiquidation.partialLiquidationParams({
|
|
351
363
|
suite,
|
|
352
364
|
account: ca,
|
|
353
365
|
overrides,
|
|
354
|
-
exclude: (token) => this.#
|
|
366
|
+
exclude: (token) => this.#isUnseizable(suite, token)
|
|
355
367
|
});
|
|
356
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* The facade reverts when a phantom tokenOut unwraps to the underlying
|
|
371
|
+
**/
|
|
372
|
+
#isUnseizable(suite, token) {
|
|
373
|
+
return this.#isWithdrawalPhantom(token) || (0, viem.isAddressEqual)(this.sdk.tokensMeta.depositedToken(token), suite.underlying);
|
|
374
|
+
}
|
|
357
375
|
async #getCreditAccountData(creditAccount, blockNumber) {
|
|
358
376
|
const ca = await this.sdk.accounts.getCreditAccountData(creditAccount, blockNumber);
|
|
359
377
|
if (!ca) throw new Error(`credit account ${creditAccount} not found`);
|
|
@@ -426,7 +444,6 @@ var LiquidationsService = class extends require_onchain_base_SDKConstruct.SDKCon
|
|
|
426
444
|
};
|
|
427
445
|
}
|
|
428
446
|
#isPartiallyLiquidatable(ca, suite) {
|
|
429
|
-
if (suite.market.rwa) return false;
|
|
430
447
|
try {
|
|
431
448
|
return this.#getPartialLiquidationParams(ca, suite, {}).isPartiallyLiquidatable;
|
|
432
449
|
} catch (e) {
|
|
@@ -7,7 +7,7 @@ const MERKL_API_KEY_HEADER = "X-API-Key";
|
|
|
7
7
|
* Merkl has no timeout of its own, and a hung connection would otherwise stall
|
|
8
8
|
* its leg of a fan-out for as long as the socket lives.
|
|
9
9
|
*/
|
|
10
|
-
const TIMEOUT =
|
|
10
|
+
const TIMEOUT = 3e4;
|
|
11
11
|
/**
|
|
12
12
|
* The wallet's raw Merkl rewards on one chain.
|
|
13
13
|
*
|
|
@@ -3,7 +3,7 @@ const require_sdk_rewards_errors = require("./errors.js");
|
|
|
3
3
|
//#region src/sdk/rewards/turtle-api.ts
|
|
4
4
|
const TURTLE_API_URL = "https://earn.turtle.xyz";
|
|
5
5
|
const GEARBOX_ORG_ID = "d171ba3d-ff89-4e6c-8f13-d94840b06edd";
|
|
6
|
-
const TIMEOUT =
|
|
6
|
+
const TIMEOUT = 3e4;
|
|
7
7
|
const turtleStreamAbi = [{
|
|
8
8
|
type: "function",
|
|
9
9
|
name: "getClaimedRewards",
|
|
@@ -22,6 +22,7 @@ import "../../market/index.js";
|
|
|
22
22
|
import { LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./constants.js";
|
|
23
23
|
import { optimalPartialLiquidation, partialLiquidationParams } from "./partialLiquidation.js";
|
|
24
24
|
import { skipLiquidatableAccount } from "./skipLiquidatableAccount.js";
|
|
25
|
+
import { isAddressEqual } from "viem";
|
|
25
26
|
//#region src/onchain/accounts/liquidations/LiquidationsService.ts
|
|
26
27
|
/**
|
|
27
28
|
* Service for discovering liquidatable credit accounts and previewing manual
|
|
@@ -120,14 +121,15 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
120
121
|
* full one: what the liquidator pays, what it receives and what it must
|
|
121
122
|
* approve, plus {@link LiquidationDetails.isPartiallyLiquidatable}.
|
|
122
123
|
*
|
|
123
|
-
* A local estimate
|
|
124
|
-
*
|
|
124
|
+
* A local estimate, not onchain read: no price feed updates are applied, so
|
|
125
|
+
* `ignoreReservePrices` has no effect here.
|
|
126
|
+
* Parameters left out of `props` are derived from current state.
|
|
125
127
|
*
|
|
126
|
-
* @throws For
|
|
127
|
-
* `tokenOut` can be picked.
|
|
128
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), for a
|
|
129
|
+
* `tokenOut` that cannot be seized, and when no `tokenOut` can be picked.
|
|
128
130
|
**/
|
|
129
131
|
async getPartialLiquidationDetails(props) {
|
|
130
|
-
const { creditAccount, blockNumber } = props;
|
|
132
|
+
const { creditAccount, liquidator, blockNumber } = props;
|
|
131
133
|
const ca = await this.#getCreditAccountData(creditAccount, blockNumber);
|
|
132
134
|
const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
133
135
|
const { priceOracle } = suite.market;
|
|
@@ -136,6 +138,13 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
136
138
|
const { liquidationDiscount } = suite.liquidationFees();
|
|
137
139
|
const seizedValue = repaidAmount * PERCENTAGE_FACTOR / BigInt(liquidationDiscount);
|
|
138
140
|
const seizedAmount = priceOracle.convert(underlying, tokenOut, repaidAmount) * PERCENTAGE_FACTOR / BigInt(liquidationDiscount);
|
|
141
|
+
const nft = await suite.degenNFT();
|
|
142
|
+
let isLiquidatorEligible = !nft;
|
|
143
|
+
if (nft && liquidator) {
|
|
144
|
+
const requirements = await nft.getOpenAccountRequirements(liquidator, { tokenOutAddress: tokenOut });
|
|
145
|
+
isLiquidatorEligible = nft.isRegistered(requirements);
|
|
146
|
+
}
|
|
147
|
+
const [kycToken] = nft && !isLiquidatorEligible ? await nft.getTokens() : [];
|
|
139
148
|
return {
|
|
140
149
|
...this.#buildAccount(ca, suite),
|
|
141
150
|
repaymentAmount: priceOracle.toTokenAmount(underlying, repaidAmount),
|
|
@@ -146,7 +155,9 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
146
155
|
...priceOracle.toTokenAmount(tokenOut, seizedAmount),
|
|
147
156
|
token: this.sdk.tokensMeta.mustGetToken(this.sdk.tokensMeta.depositedToken(tokenOut))
|
|
148
157
|
}],
|
|
149
|
-
isLiquidatorEligible
|
|
158
|
+
isLiquidatorEligible,
|
|
159
|
+
kycProtocol: isLiquidatorEligible ? void 0 : nft?.protocol,
|
|
160
|
+
kycToken: kycToken ? this.sdk.tokensMeta.getToken(kycToken) : void 0,
|
|
150
161
|
isCreditAccountFrozen: false,
|
|
151
162
|
approve: repaidAmount === 0n ? void 0 : {
|
|
152
163
|
spender: suite.creditManager.address,
|
|
@@ -162,17 +173,18 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
162
173
|
* discounted collateral sent to the liquidator. Parameters left out of
|
|
163
174
|
* `props` are derived from current state.
|
|
164
175
|
*
|
|
165
|
-
* @throws For
|
|
166
|
-
* `tokenOut`
|
|
167
|
-
* liquidated, see
|
|
176
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), for a
|
|
177
|
+
* `tokenOut` that cannot be seized, when no `tokenOut` can be picked, and
|
|
178
|
+
* when the account cannot be partially liquidated, see
|
|
179
|
+
* {@link LiquidationDetails.isPartiallyLiquidatable}.
|
|
168
180
|
**/
|
|
169
181
|
async buildPartialLiquidationTx(props) {
|
|
170
|
-
const { creditAccount, liquidator, blockNumber } = props;
|
|
182
|
+
const { creditAccount, liquidator, ignoreReservePrices, blockNumber } = props;
|
|
171
183
|
const ca = await this.#getCreditAccountData(creditAccount, blockNumber);
|
|
172
184
|
const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
173
185
|
const params = this.#getPartialLiquidationParams(ca, suite, props);
|
|
174
186
|
if (!params.isPartiallyLiquidatable) throw new Error(`credit account ${this.labelAddress(creditAccount)} cannot be partially liquidated`);
|
|
175
|
-
const updates = await this.sdk.accounts.getOnDemandPriceUpdates(ca,
|
|
187
|
+
const updates = await this.sdk.accounts.getOnDemandPriceUpdates(ca, ignoreReservePrices);
|
|
176
188
|
const tx = suite.creditFacade.partiallyLiquidateCreditAccount(ca.creditAccount, params.tokenOut, params.repaidAmount, params.minSeizedAmount, liquidator, updates);
|
|
177
189
|
this.logger?.debug(`built tx to partially liquidate credit account ${this.labelAddress(creditAccount)} to ${this.labelAddress(liquidator)}`);
|
|
178
190
|
return {
|
|
@@ -184,9 +196,6 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
184
196
|
* Optimal partial liquidation of a credit account: the collateral to seize
|
|
185
197
|
* and the amounts that bring its health factor close to `optimalHF`.
|
|
186
198
|
*
|
|
187
|
-
* Prices come from the last synced oracle state and `ca`, not from fresh
|
|
188
|
-
* price updates. Withdrawal phantom tokens are never seized.
|
|
189
|
-
*
|
|
190
199
|
* @param ca - Credit account to partially liquidate.
|
|
191
200
|
* @param optimalHF - Health factor to aim for, in basis points. Defaults to
|
|
192
201
|
* {@link CreditSuite.optimalHFForPartialLiquidation}.
|
|
@@ -195,11 +204,12 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
195
204
|
* @throws If no `tokenOut` can be picked.
|
|
196
205
|
**/
|
|
197
206
|
getOptimalPartialLiquidation(ca, optimalHF, liquidationThresholds) {
|
|
207
|
+
const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
198
208
|
return optimalPartialLiquidation({
|
|
199
|
-
suite
|
|
209
|
+
suite,
|
|
200
210
|
account: ca,
|
|
201
211
|
optimalHF,
|
|
202
|
-
exclude: (token) => this.#
|
|
212
|
+
exclude: (token) => this.#isUnseizable(suite, token),
|
|
203
213
|
liquidationThresholds
|
|
204
214
|
});
|
|
205
215
|
}
|
|
@@ -335,24 +345,32 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
335
345
|
/**
|
|
336
346
|
* Everything a partial liquidation of a credit account needs, with any
|
|
337
347
|
* parameter the caller pinned down taken as given and the rest derived from
|
|
338
|
-
* current state. A derived `tokenOut` is never a
|
|
348
|
+
* current state. A derived `tokenOut` is never a token that cannot be seized.
|
|
339
349
|
*
|
|
340
|
-
* @throws For
|
|
341
|
-
* the
|
|
342
|
-
* which does not redeem instantly,
|
|
343
|
-
*
|
|
350
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), whose
|
|
351
|
+
* repayment the liquidator cannot fund, for a `tokenOut` that cannot be
|
|
352
|
+
* seized (a withdrawal phantom token, which does not redeem instantly, or a
|
|
353
|
+
* phantom token that unwraps to the underlying), if a derived `tokenOut`
|
|
354
|
+
* cannot be picked, and if the seized token is not a collateral token of the
|
|
355
|
+
* credit manager.
|
|
344
356
|
**/
|
|
345
357
|
#getPartialLiquidationParams(ca, suite, overrides) {
|
|
346
358
|
const label = this.labelAddress(ca.creditAccount);
|
|
347
|
-
if (suite.
|
|
348
|
-
if (overrides.tokenOut && this.#
|
|
359
|
+
if (this.sdk.tokensMeta.isRWAUnderlying(this.sdk.tokensMeta.mustGet(suite.underlying))) throw new Error(`cannot partially liquidate ${label}: markets with a wrapped RWA underlying are not supported`);
|
|
360
|
+
if (overrides.tokenOut && this.#isUnseizable(suite, overrides.tokenOut)) throw new Error(`cannot partially liquidate ${label}: ${this.labelAddress(overrides.tokenOut)} cannot be seized`);
|
|
349
361
|
return partialLiquidationParams({
|
|
350
362
|
suite,
|
|
351
363
|
account: ca,
|
|
352
364
|
overrides,
|
|
353
|
-
exclude: (token) => this.#
|
|
365
|
+
exclude: (token) => this.#isUnseizable(suite, token)
|
|
354
366
|
});
|
|
355
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* The facade reverts when a phantom tokenOut unwraps to the underlying
|
|
370
|
+
**/
|
|
371
|
+
#isUnseizable(suite, token) {
|
|
372
|
+
return this.#isWithdrawalPhantom(token) || isAddressEqual(this.sdk.tokensMeta.depositedToken(token), suite.underlying);
|
|
373
|
+
}
|
|
356
374
|
async #getCreditAccountData(creditAccount, blockNumber) {
|
|
357
375
|
const ca = await this.sdk.accounts.getCreditAccountData(creditAccount, blockNumber);
|
|
358
376
|
if (!ca) throw new Error(`credit account ${creditAccount} not found`);
|
|
@@ -425,7 +443,6 @@ var LiquidationsService = class extends SDKConstruct {
|
|
|
425
443
|
};
|
|
426
444
|
}
|
|
427
445
|
#isPartiallyLiquidatable(ca, suite) {
|
|
428
|
-
if (suite.market.rwa) return false;
|
|
429
446
|
try {
|
|
430
447
|
return this.#getPartialLiquidationParams(ca, suite, {}).isPartiallyLiquidatable;
|
|
431
448
|
} catch (e) {
|
|
@@ -6,7 +6,7 @@ const MERKL_API_KEY_HEADER = "X-API-Key";
|
|
|
6
6
|
* Merkl has no timeout of its own, and a hung connection would otherwise stall
|
|
7
7
|
* its leg of a fan-out for as long as the socket lives.
|
|
8
8
|
*/
|
|
9
|
-
const TIMEOUT =
|
|
9
|
+
const TIMEOUT = 3e4;
|
|
10
10
|
/**
|
|
11
11
|
* The wallet's raw Merkl rewards on one chain.
|
|
12
12
|
*
|
|
@@ -2,7 +2,7 @@ import { TurtleRequestFailedError } from "./errors.js";
|
|
|
2
2
|
//#region src/sdk/rewards/turtle-api.ts
|
|
3
3
|
const TURTLE_API_URL = "https://earn.turtle.xyz";
|
|
4
4
|
const GEARBOX_ORG_ID = "d171ba3d-ff89-4e6c-8f13-d94840b06edd";
|
|
5
|
-
const TIMEOUT =
|
|
5
|
+
const TIMEOUT = 3e4;
|
|
6
6
|
const turtleStreamAbi = [{
|
|
7
7
|
type: "function",
|
|
8
8
|
name: "getClaimedRewards",
|
|
@@ -95,10 +95,9 @@ export interface LiquidatableAccount extends CreditOperationMarket {
|
|
|
95
95
|
rwa: boolean;
|
|
96
96
|
/**
|
|
97
97
|
* Whether the account can be partially liquidated with default parameters.
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* without leaving it with less than the minimum debt.
|
|
98
|
+
*
|
|
99
|
+
* Independent of the liquidator: a KYC gate (e.g. Midas greenlist) is
|
|
100
|
+
* reported by {@link LiquidationDetails.isLiquidatorEligible}, not here.
|
|
102
101
|
*
|
|
103
102
|
* A local estimate, not onchain read.
|
|
104
103
|
**/
|
|
@@ -43,11 +43,12 @@ export declare class LiquidationsService extends SDKConstruct {
|
|
|
43
43
|
* full one: what the liquidator pays, what it receives and what it must
|
|
44
44
|
* approve, plus {@link LiquidationDetails.isPartiallyLiquidatable}.
|
|
45
45
|
*
|
|
46
|
-
* A local estimate
|
|
47
|
-
*
|
|
46
|
+
* A local estimate, not onchain read: no price feed updates are applied, so
|
|
47
|
+
* `ignoreReservePrices` has no effect here.
|
|
48
|
+
* Parameters left out of `props` are derived from current state.
|
|
48
49
|
*
|
|
49
|
-
* @throws For
|
|
50
|
-
* `tokenOut` can be picked.
|
|
50
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), for a
|
|
51
|
+
* `tokenOut` that cannot be seized, and when no `tokenOut` can be picked.
|
|
51
52
|
**/
|
|
52
53
|
getPartialLiquidationDetails(props: GetPartialLiquidationDetailsProps): Promise<LiquidationDetails>;
|
|
53
54
|
/**
|
|
@@ -56,18 +57,16 @@ export declare class LiquidationsService extends SDKConstruct {
|
|
|
56
57
|
* discounted collateral sent to the liquidator. Parameters left out of
|
|
57
58
|
* `props` are derived from current state.
|
|
58
59
|
*
|
|
59
|
-
* @throws For
|
|
60
|
-
* `tokenOut`
|
|
61
|
-
* liquidated, see
|
|
60
|
+
* @throws For markets with a wrapped RWA underlying (Securitize), for a
|
|
61
|
+
* `tokenOut` that cannot be seized, when no `tokenOut` can be picked, and
|
|
62
|
+
* when the account cannot be partially liquidated, see
|
|
63
|
+
* {@link LiquidationDetails.isPartiallyLiquidatable}.
|
|
62
64
|
**/
|
|
63
65
|
buildPartialLiquidationTx(props: BuildPartialLiquidationTxProps): Promise<TxCall>;
|
|
64
66
|
/**
|
|
65
67
|
* Optimal partial liquidation of a credit account: the collateral to seize
|
|
66
68
|
* and the amounts that bring its health factor close to `optimalHF`.
|
|
67
69
|
*
|
|
68
|
-
* Prices come from the last synced oracle state and `ca`, not from fresh
|
|
69
|
-
* price updates. Withdrawal phantom tokens are never seized.
|
|
70
|
-
*
|
|
71
70
|
* @param ca - Credit account to partially liquidate.
|
|
72
71
|
* @param optimalHF - Health factor to aim for, in basis points. Defaults to
|
|
73
72
|
* {@link CreditSuite.optimalHFForPartialLiquidation}.
|
|
@@ -46,16 +46,15 @@ export interface GetLiquidationDetailsPropsBase {
|
|
|
46
46
|
**/
|
|
47
47
|
creditAccount: Address;
|
|
48
48
|
/**
|
|
49
|
-
* Liquidator wallet address, used
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* (see {@link LiquidationDetails.kycProtocol}).
|
|
49
|
+
* Liquidator wallet address, used to check KYC eligibility. Amounts and
|
|
50
|
+
* received assets are unaffected. When omitted,
|
|
51
|
+
* {@link LiquidationDetails.isLiquidatorEligible} only tells whether the
|
|
52
|
+
* liquidation is KYC-gated at all (see {@link LiquidationDetails.kycProtocol}).
|
|
54
53
|
**/
|
|
55
54
|
liquidator?: Address;
|
|
56
55
|
/**
|
|
57
56
|
* If true, reserve price feed updates are excluded from the price updates
|
|
58
|
-
* applied
|
|
57
|
+
* applied before computing amounts.
|
|
59
58
|
**/
|
|
60
59
|
ignoreReservePrices?: boolean;
|
|
61
60
|
/**
|
|
@@ -85,7 +84,7 @@ export interface BuildLiquidationTxPropsBase {
|
|
|
85
84
|
liquidator: Address;
|
|
86
85
|
/**
|
|
87
86
|
* If true, reserve price feed updates are excluded from the price updates
|
|
88
|
-
* applied
|
|
87
|
+
* applied before building the transaction.
|
|
89
88
|
**/
|
|
90
89
|
ignoreReservePrices?: boolean;
|
|
91
90
|
/**
|
|
@@ -156,16 +155,7 @@ export interface FullyLiquidateResult {
|
|
|
156
155
|
* Parameters left out are derived from current state, see
|
|
157
156
|
* {@link PartialLiquidationParams}.
|
|
158
157
|
**/
|
|
159
|
-
export interface GetPartialLiquidationDetailsPropsBase extends Partial<PartialLiquidationParams> {
|
|
160
|
-
/**
|
|
161
|
-
* Credit account to partially liquidate.
|
|
162
|
-
**/
|
|
163
|
-
creditAccount: Address;
|
|
164
|
-
/**
|
|
165
|
-
* Block to read at. Defaults to the latest block.
|
|
166
|
-
**/
|
|
167
|
-
blockNumber?: bigint;
|
|
168
|
-
}
|
|
158
|
+
export interface GetPartialLiquidationDetailsPropsBase extends GetLiquidationDetailsPropsBase, Partial<PartialLiquidationParams> {}
|
|
169
159
|
/**
|
|
170
160
|
* Props for {@link LiquidationsService.getPartialLiquidationDetails}.
|
|
171
161
|
*
|
|
@@ -179,21 +169,7 @@ export type GetPartialLiquidationDetailsProps<Multichain extends boolean = false
|
|
|
179
169
|
* Parameters left out are derived from current state, see
|
|
180
170
|
* {@link PartialLiquidationParams}.
|
|
181
171
|
**/
|
|
182
|
-
export interface BuildPartialLiquidationTxPropsBase extends Partial<PartialLiquidationParams> {
|
|
183
|
-
/**
|
|
184
|
-
* Credit account to partially liquidate.
|
|
185
|
-
**/
|
|
186
|
-
creditAccount: Address;
|
|
187
|
-
/**
|
|
188
|
-
* Liquidator wallet address. Required: it is encoded into the transaction
|
|
189
|
-
* as the receiver of the seized collateral.
|
|
190
|
-
**/
|
|
191
|
-
liquidator: Address;
|
|
192
|
-
/**
|
|
193
|
-
* Block to read at. Defaults to the latest block.
|
|
194
|
-
**/
|
|
195
|
-
blockNumber?: bigint;
|
|
196
|
-
}
|
|
172
|
+
export interface BuildPartialLiquidationTxPropsBase extends BuildLiquidationTxPropsBase, Partial<PartialLiquidationParams> {}
|
|
197
173
|
/**
|
|
198
174
|
* Props for {@link LiquidationsService.buildPartialLiquidationTx}.
|
|
199
175
|
*
|
|
@@ -233,7 +209,8 @@ export interface PartialLiquidationParams {
|
|
|
233
209
|
/**
|
|
234
210
|
* Collateral token to seize.
|
|
235
211
|
* Defaults to the most valuable enabled non-underlying collateral token
|
|
236
|
-
* (by oracle), excluding withdrawal phantom tokens
|
|
212
|
+
* (by oracle), excluding withdrawal phantom tokens and phantom tokens that
|
|
213
|
+
* unwrap to the underlying
|
|
237
214
|
*/
|
|
238
215
|
tokenOut: Address;
|
|
239
216
|
/**
|