@gearbox-protocol/sdk 16.3.2 → 16.4.0-next.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/dist/cjs/dev/midasUtils.js +11 -46
- package/dist/cjs/model/errors/index.js +1 -0
- package/dist/cjs/model/errors/operation-errors.js +9 -0
- package/dist/cjs/model/index.js +1 -0
- package/dist/cjs/onchain/accounts/intents/collateral-money.js +41 -0
- package/dist/cjs/onchain/accounts/intents/guards.js +15 -3
- package/dist/cjs/onchain/accounts/intents/index.js +21 -18
- package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +12 -38
- package/dist/cjs/onchain/accounts/intents/realize.js +10 -2
- package/dist/cjs/onchain/accounts/intents/tail.js +1 -1
- package/dist/cjs/onchain/accounts/intents/withdraw-limits.js +97 -0
- package/dist/cjs/onchain/index.js +2 -0
- package/dist/cjs/onchain/market/adapters/abi/conctructorAbi.js +1 -1
- package/dist/cjs/onchain/preview/preview/previewOpenStrategyPosition.js +10 -16
- package/dist/cjs/onchain/preview/preview/previewOperation.js +19 -11
- package/dist/cjs/onchain/preview/preview/replayMulticall.js +4 -3
- package/dist/cjs/onchain/validation/bundles/checkCollateralFunding.js +3 -3
- package/dist/cjs/onchain/validation/bundles/checkCreditOperation.js +4 -3
- package/dist/cjs/onchain/validation/bundles/checkRWAOpening.js +1 -2
- package/dist/cjs/onchain/validation/checkOperation.js +0 -1
- package/dist/cjs/onchain/validation/checks/checkReservePriceLimited.js +30 -0
- package/dist/cjs/onchain/validation/checks/index.js +2 -0
- package/dist/cjs/onchain/validation/index.js +2 -0
- package/dist/cjs/sdk/prepare/PrepareApi.js +3 -2
- package/dist/esm/dev/midasUtils.js +12 -47
- package/dist/esm/model/errors/index.js +2 -2
- package/dist/esm/model/errors/operation-errors.js +9 -1
- package/dist/esm/model/index.js +2 -2
- package/dist/esm/onchain/accounts/intents/collateral-money.js +40 -0
- package/dist/esm/onchain/accounts/intents/guards.js +15 -3
- package/dist/esm/onchain/accounts/intents/index.js +21 -18
- package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +12 -38
- package/dist/esm/onchain/accounts/intents/realize.js +10 -2
- package/dist/esm/onchain/accounts/intents/tail.js +1 -1
- package/dist/esm/onchain/accounts/intents/withdraw-limits.js +95 -0
- package/dist/esm/onchain/index.js +2 -1
- package/dist/esm/onchain/market/adapters/abi/conctructorAbi.js +1 -1
- package/dist/esm/onchain/preview/preview/previewOpenStrategyPosition.js +11 -17
- package/dist/esm/onchain/preview/preview/previewOperation.js +19 -11
- package/dist/esm/onchain/preview/preview/replayMulticall.js +4 -3
- package/dist/esm/onchain/validation/bundles/checkCollateralFunding.js +3 -3
- package/dist/esm/onchain/validation/bundles/checkCreditOperation.js +4 -3
- package/dist/esm/onchain/validation/bundles/checkRWAOpening.js +1 -2
- package/dist/esm/onchain/validation/checkOperation.js +0 -1
- package/dist/esm/onchain/validation/checks/checkReservePriceLimited.js +29 -0
- package/dist/esm/onchain/validation/checks/index.js +2 -1
- package/dist/esm/onchain/validation/index.js +2 -1
- package/dist/esm/sdk/prepare/PrepareApi.js +3 -2
- package/dist/types/dev/midasUtils.d.ts +3 -4
- package/dist/types/model/errors/index.d.ts +2 -2
- package/dist/types/model/errors/operation-errors.d.ts +41 -1
- package/dist/types/model/index.d.ts +3 -3
- package/dist/types/model/previews.d.ts +11 -20
- package/dist/types/onchain/accounts/intents/collateral-money.d.ts +42 -0
- package/dist/types/onchain/accounts/intents/guards.d.ts +18 -2
- package/dist/types/onchain/accounts/intents/index.d.ts +23 -14
- package/dist/types/onchain/accounts/intents/maxWithdrawCollateral.d.ts +3 -8
- package/dist/types/onchain/accounts/intents/types.d.ts +26 -4
- package/dist/types/onchain/accounts/intents/withdraw-limits.d.ts +80 -0
- package/dist/types/onchain/index.d.ts +2 -1
- package/dist/types/onchain/preview/preview/previewOpenStrategyPosition.d.ts +5 -3
- package/dist/types/onchain/preview/preview/replayMulticall.d.ts +8 -7
- package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -2
- package/dist/types/onchain/validation/checks/checkReservePriceLimited.d.ts +31 -0
- package/dist/types/onchain/validation/checks/index.d.ts +2 -1
- package/dist/types/onchain/validation/index.d.ts +2 -1
- package/dist/types/onchain/validation/raise.d.ts +2 -2
- package/dist/types/sdk/prepare/PrepareApi.d.ts +1 -1
- package/dist/types/sdk/prepare/types.d.ts +23 -16
- package/package.json +1 -1
|
@@ -10,24 +10,14 @@ const iMidasPausableVaultAbi = (0, viem.parseAbi)([
|
|
|
10
10
|
"function paused() external view returns (bool)",
|
|
11
11
|
"function pause() external",
|
|
12
12
|
"function unpause() external",
|
|
13
|
-
"function fnPaused(bytes4 fn) external view returns (bool)",
|
|
14
|
-
"function pauseFn(bytes4 fn) external",
|
|
15
|
-
"function unpauseFn(bytes4 fn) external",
|
|
16
13
|
"function pauseAdminRole() external view returns (bytes32)",
|
|
17
14
|
"function accessControl() external view returns (address)"
|
|
18
15
|
]);
|
|
19
16
|
const iMidasAccessControlAbi = (0, viem.parseAbi)(["function hasRole(bytes32 role, address account) external view returns (bool)", "function grantRole(bytes32 role, address account) external"]);
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*/
|
|
25
|
-
const DEPOSIT_INSTANT_SELECTOR = (0, viem.toFunctionSelector)("depositInstant(address,uint256,uint256,bytes32)");
|
|
26
|
-
/**
|
|
27
|
-
* Unpauses a Midas issuance vault on an anvil fork so that `depositInstant`
|
|
28
|
-
* stops reverting with `Pausable: paused` (global) or `Pausable: fn paused`
|
|
29
|
-
* (per-selector), and returns a callback that restores the original pause
|
|
30
|
-
* state of each layer that was cleared.
|
|
18
|
+
* Unpauses a globally paused Midas issuance vault on an anvil fork, so that
|
|
19
|
+
* `depositInstant` stops reverting with `Pausable: paused`, and returns a
|
|
20
|
+
* callback that restores the original pause state.
|
|
31
21
|
*
|
|
32
22
|
* Impersonates `admin` and grants it `pauseAdminRole()` when missing, same as
|
|
33
23
|
* `greenlistMidasGateway` does with the greenlist roles. The grant is not
|
|
@@ -35,20 +25,11 @@ const DEPOSIT_INSTANT_SELECTOR = (0, viem.toFunctionSelector)("depositInstant(ad
|
|
|
35
25
|
*/
|
|
36
26
|
async function unpauseMidasIssuanceVault(props) {
|
|
37
27
|
const { anvil, vault, admin, logger } = props;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
functionName: "paused"
|
|
44
|
-
}, {
|
|
45
|
-
address: vault,
|
|
46
|
-
abi: iMidasPausableVaultAbi,
|
|
47
|
-
functionName: "fnPaused",
|
|
48
|
-
args: [DEPOSIT_INSTANT_SELECTOR]
|
|
49
|
-
}]
|
|
50
|
-
});
|
|
51
|
-
if (!paused && !depositInstantPaused) {
|
|
28
|
+
if (!await anvil.readContract({
|
|
29
|
+
address: vault,
|
|
30
|
+
abi: iMidasPausableVaultAbi,
|
|
31
|
+
functionName: "paused"
|
|
32
|
+
})) {
|
|
52
33
|
logger?.debug(`midas: issuance vault ${vault} is not paused`);
|
|
53
34
|
return async () => {};
|
|
54
35
|
}
|
|
@@ -70,7 +51,7 @@ async function unpauseMidasIssuanceVault(props) {
|
|
|
70
51
|
functionName: "hasRole",
|
|
71
52
|
args: [pauseAdminRole, admin]
|
|
72
53
|
});
|
|
73
|
-
logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}`
|
|
54
|
+
logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}`);
|
|
74
55
|
await anvil.impersonateAccount({ address: admin });
|
|
75
56
|
try {
|
|
76
57
|
await anvil.setBalance({
|
|
@@ -88,21 +69,13 @@ async function unpauseMidasIssuanceVault(props) {
|
|
|
88
69
|
});
|
|
89
70
|
logger?.debug(`midas: granted pause admin role to ${admin}`);
|
|
90
71
|
}
|
|
91
|
-
|
|
72
|
+
await require_dev_kycUtils.writeAndWait(anvil, {
|
|
92
73
|
account: admin,
|
|
93
74
|
chain: anvil.chain,
|
|
94
75
|
address: vault,
|
|
95
76
|
abi: iMidasPausableVaultAbi,
|
|
96
77
|
functionName: "unpause"
|
|
97
78
|
});
|
|
98
|
-
if (depositInstantPaused) await require_dev_kycUtils.writeAndWait(anvil, {
|
|
99
|
-
account: admin,
|
|
100
|
-
chain: anvil.chain,
|
|
101
|
-
address: vault,
|
|
102
|
-
abi: iMidasPausableVaultAbi,
|
|
103
|
-
functionName: "unpauseFn",
|
|
104
|
-
args: [DEPOSIT_INSTANT_SELECTOR]
|
|
105
|
-
});
|
|
106
79
|
} finally {
|
|
107
80
|
await anvil.stopImpersonatingAccount({ address: admin });
|
|
108
81
|
}
|
|
@@ -117,21 +90,13 @@ async function unpauseMidasIssuanceVault(props) {
|
|
|
117
90
|
address: admin,
|
|
118
91
|
value: (0, viem.parseEther)("100")
|
|
119
92
|
});
|
|
120
|
-
|
|
93
|
+
await require_dev_kycUtils.writeAndWait(anvil, {
|
|
121
94
|
account: admin,
|
|
122
95
|
chain: anvil.chain,
|
|
123
96
|
address: vault,
|
|
124
97
|
abi: iMidasPausableVaultAbi,
|
|
125
98
|
functionName: "pause"
|
|
126
99
|
});
|
|
127
|
-
if (depositInstantPaused) await require_dev_kycUtils.writeAndWait(anvil, {
|
|
128
|
-
account: admin,
|
|
129
|
-
chain: anvil.chain,
|
|
130
|
-
address: vault,
|
|
131
|
-
abi: iMidasPausableVaultAbi,
|
|
132
|
-
functionName: "pauseFn",
|
|
133
|
-
args: [DEPOSIT_INSTANT_SELECTOR]
|
|
134
|
-
});
|
|
135
100
|
} catch (e) {
|
|
136
101
|
logger?.warn(`midas: failed to pause issuance vault ${vault} back: ${e}`);
|
|
137
102
|
} finally {
|
|
@@ -28,6 +28,7 @@ exports.poolPaused = require_model_errors_operation_errors.poolPaused;
|
|
|
28
28
|
exports.poolSunset = require_model_errors_operation_errors.poolSunset;
|
|
29
29
|
exports.quotaCountExceeded = require_model_errors_operation_errors.quotaCountExceeded;
|
|
30
30
|
exports.quotaLimitReached = require_model_errors_operation_errors.quotaLimitReached;
|
|
31
|
+
exports.reservePriceLimited = require_model_errors_operation_errors.reservePriceLimited;
|
|
31
32
|
exports.rwaOpenRequirementsNotMet = require_model_errors_operation_errors.rwaOpenRequirementsNotMet;
|
|
32
33
|
exports.unexpectedFailure = require_model_errors_prepare_errors.unexpectedFailure;
|
|
33
34
|
exports.unpriceableTokenError = require_model_errors_oracle_errors.unpriceableTokenError;
|
|
@@ -67,6 +67,14 @@ function insufficientCollateral(args) {
|
|
|
67
67
|
...args
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
+
/** {@inheritDoc ReservePriceLimitedError} */
|
|
71
|
+
function reservePriceLimited(args) {
|
|
72
|
+
return {
|
|
73
|
+
code: "reservePriceLimited",
|
|
74
|
+
message: `The reserve price feed values this collateral below what the operation pays out: the account covers its debt at ${args.atMainPrices} on the main feed and only ${args.healthFactor} at the reserve one, below ${args.healthFactorThreshold}.`,
|
|
75
|
+
...args
|
|
76
|
+
};
|
|
77
|
+
}
|
|
70
78
|
/** {@inheritDoc ForbiddenTokenError} */
|
|
71
79
|
function forbiddenToken(token) {
|
|
72
80
|
return {
|
|
@@ -132,4 +140,5 @@ exports.poolPaused = poolPaused;
|
|
|
132
140
|
exports.poolSunset = poolSunset;
|
|
133
141
|
exports.quotaCountExceeded = quotaCountExceeded;
|
|
134
142
|
exports.quotaLimitReached = quotaLimitReached;
|
|
143
|
+
exports.reservePriceLimited = reservePriceLimited;
|
|
135
144
|
exports.rwaOpenRequirementsNotMet = rwaOpenRequirementsNotMet;
|
package/dist/cjs/model/index.js
CHANGED
|
@@ -175,6 +175,7 @@ exports.quotaLimitReached = require_model_errors_operation_errors.quotaLimitReac
|
|
|
175
175
|
exports.rateCurvePointSchema = require_model_opportunities_schema.rateCurvePointSchema;
|
|
176
176
|
exports.rateCurveSchema = require_model_opportunities_schema.rateCurveSchema;
|
|
177
177
|
exports.receivedAssetSchema = require_model_liquidations_schema.receivedAssetSchema;
|
|
178
|
+
exports.reservePriceLimited = require_model_errors_operation_errors.reservePriceLimited;
|
|
178
179
|
exports.responseMetadataSchema = require_model_response_schema.responseMetadataSchema;
|
|
179
180
|
exports.responseSchema = require_model_response_schema.responseSchema;
|
|
180
181
|
exports.rewardsPnLSchema = require_model_positions_schema.rewardsPnLSchema;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_onchain_utils_bigint_math = require("../../utils/bigint-math.js");
|
|
3
|
+
const require_onchain_constants_math = require("../../constants/math.js");
|
|
4
|
+
require("../../utils/index.js");
|
|
5
|
+
const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
|
|
6
|
+
//#region src/onchain/accounts/intents/collateral-money.ts
|
|
7
|
+
/** {@inheritDoc CollateralMoney} */
|
|
8
|
+
function collateralMoney(creditAccount, sdk) {
|
|
9
|
+
const { market, creditManager } = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
|
|
10
|
+
const { priceOracle } = market;
|
|
11
|
+
const { pqk } = market.pool;
|
|
12
|
+
const underlying = market.pool.underlying;
|
|
13
|
+
const masked = creditAccount.enabledTokensMask !== 0n;
|
|
14
|
+
const mainUsd = (token, amount) => {
|
|
15
|
+
try {
|
|
16
|
+
return priceOracle.convertToUSD(token, amount);
|
|
17
|
+
} catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const lt = (token) => BigInt(creditManager.liquidationThresholds.get(token) ?? 0);
|
|
22
|
+
const checkedUsd = (holding) => require_onchain_accounts_intents_utils_common.eq(holding.token, underlying) ? mainUsd(holding.token, holding.balance) ?? 0n : priceOracle.safeConvertMinUSD(holding.token, holding.balance).value;
|
|
23
|
+
/** A quota is underlying-denominated, and a closed market backs nothing. */
|
|
24
|
+
const quotaMoney = (holding) => pqk.hasActiveQuota(holding.token) ? (mainUsd(underlying, holding.quota) ?? 0n) * require_onchain_constants_math.PERCENTAGE_FACTOR : 0n;
|
|
25
|
+
const weigh = (holding) => {
|
|
26
|
+
const weighted = checkedUsd(holding) * lt(holding.token);
|
|
27
|
+
if (holding.quota === 0n) return weighted;
|
|
28
|
+
return require_onchain_utils_bigint_math.BigIntMath.min(quotaMoney(holding), weighted);
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
underlying,
|
|
32
|
+
counts: (holding) => holding.balance > 10n && (!masked || (holding.mask & creditAccount.enabledTokensMask) !== 0n),
|
|
33
|
+
weigh,
|
|
34
|
+
quotaMoney,
|
|
35
|
+
mainUsd,
|
|
36
|
+
checkedUsd,
|
|
37
|
+
lt
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.collateralMoney = collateralMoney;
|
|
@@ -7,6 +7,7 @@ const require_onchain_validation_checks_checkCreditManagerPaused = require("../.
|
|
|
7
7
|
const require_onchain_validation_checks_checkForbiddenToken = require("../../validation/checks/checkForbiddenToken.js");
|
|
8
8
|
const require_onchain_validation_checks_checkMarketExpired = require("../../validation/checks/checkMarketExpired.js");
|
|
9
9
|
const require_onchain_validation_checks_checkQuotaLimit = require("../../validation/checks/checkQuotaLimit.js");
|
|
10
|
+
const require_onchain_validation_checks_checkReservePriceLimited = require("../../validation/checks/checkReservePriceLimited.js");
|
|
10
11
|
const require_onchain_validation_raise = require("../../validation/raise.js");
|
|
11
12
|
require("../../validation/index.js");
|
|
12
13
|
const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
|
|
@@ -112,13 +113,24 @@ function assertGrowthAllowed(args) {
|
|
|
112
113
|
* whose reserve feed the SDK cannot read keeps its main price, so a plan can
|
|
113
114
|
* still be refused on-chain after passing here.
|
|
114
115
|
*/
|
|
115
|
-
function assertCollateralised(healthFactorBps, safePrices) {
|
|
116
|
+
function assertCollateralised(healthFactorBps, safePrices, atSafePrices) {
|
|
116
117
|
const healthFactorThreshold = require_onchain_validation_helpers_health_factor_limits.MIN_HEALTH_FACTOR_FACADE;
|
|
117
|
-
|
|
118
|
+
const errors = require_onchain_validation_checks_checkCollateralised.checkCollateralised({
|
|
118
119
|
healthFactor: healthFactorBps,
|
|
119
120
|
healthFactorThreshold,
|
|
120
121
|
safePrices
|
|
121
|
-
})
|
|
122
|
+
});
|
|
123
|
+
if (errors.length === 0) return;
|
|
124
|
+
if (safePrices && atSafePrices) {
|
|
125
|
+
const { atMainPrices, withdrawable } = atSafePrices();
|
|
126
|
+
require_onchain_validation_raise.raise(require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited({
|
|
127
|
+
healthFactor: healthFactorBps,
|
|
128
|
+
atMainPrices,
|
|
129
|
+
healthFactorThreshold,
|
|
130
|
+
withdrawable
|
|
131
|
+
}), `the account covers its debt at ${atMainPrices} on the main feed and only ${healthFactorBps} at the reserve one, below ${healthFactorThreshold}`);
|
|
132
|
+
}
|
|
133
|
+
require_onchain_validation_raise.raise(errors, `the account would end at a health factor of ${healthFactorBps}, below ${healthFactorThreshold}`);
|
|
122
134
|
}
|
|
123
135
|
/**
|
|
124
136
|
* A quota can only be raised as far as the market still has room for: past the
|
|
@@ -9,13 +9,13 @@ require("../../validation/index.js");
|
|
|
9
9
|
const require_onchain_accounts_intents_utils_pick_token = require("./utils/pick-token.js");
|
|
10
10
|
const require_onchain_accounts_intents_guards = require("./guards.js");
|
|
11
11
|
const require_onchain_accounts_intents_leverage_band = require("./leverage-band.js");
|
|
12
|
-
const require_onchain_accounts_intents_math = require("./math.js");
|
|
13
12
|
const require_onchain_accounts_intents_maxWithdrawCollateral = require("./maxWithdrawCollateral.js");
|
|
14
13
|
const require_onchain_accounts_intents_utils_credit_account_slice = require("./utils/credit-account-slice.js");
|
|
15
14
|
const require_onchain_accounts_intents_open_strategy = require("./open-strategy.js");
|
|
16
15
|
const require_onchain_accounts_intents_plan = require("./plan.js");
|
|
17
|
-
const require_onchain_accounts_intents_realize = require("./realize.js");
|
|
18
16
|
const require_onchain_accounts_intents_view = require("./view.js");
|
|
17
|
+
const require_onchain_accounts_intents_withdraw_limits = require("./withdraw-limits.js");
|
|
18
|
+
const require_onchain_accounts_intents_realize = require("./realize.js");
|
|
19
19
|
const require_onchain_accounts_intents_tail = require("./tail.js");
|
|
20
20
|
//#region src/onchain/accounts/intents/index.ts
|
|
21
21
|
/**
|
|
@@ -51,26 +51,29 @@ var CreditAccountOperationsService = class extends require_onchain_base_SDKConst
|
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* Both ends of what a `WITHDRAW` can take out, in underlying: the largest
|
|
54
|
-
* partial withdrawal that keeps leverage and
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
54
|
+
* partial withdrawal that keeps leverage, and the net value an exit hands
|
|
55
|
+
* over. They are reported together because a withdraw form needs both — the
|
|
56
|
+
* range it may offer, and the one amount past it that is allowed — and
|
|
57
|
+
* because the distance between them is the account's own, not a constant a
|
|
58
|
+
* caller could assume.
|
|
59
59
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
60
|
+
* Two rules bound the partial end and both are reported: the facade's
|
|
61
|
+
* `debtLimits` as `partial`, and the safe-price collateral check on top of
|
|
62
|
+
* it as `safePartial`. The second is the one to offer — see
|
|
63
|
+
* {@link WithdrawCeilings}.
|
|
63
64
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
65
|
+
* Takes no target health factor, unlike {@link maxWithdrawCollateral}. A
|
|
66
|
+
* proportional withdrawal leaves the factor where it found it, so there is
|
|
67
|
+
* no room to choose: what these answer to is the facade's own threshold,
|
|
68
|
+
* which is also what {@link startIntent} refuses against.
|
|
69
|
+
*
|
|
70
|
+
* @param props - Account slice, the SDK holding its market, and optionally
|
|
71
|
+
* the collateral the withdrawal would be funded from
|
|
72
|
+
* @returns The three limits, see {@link WithdrawCeilings} for the gap
|
|
73
|
+
* between them
|
|
67
74
|
*/
|
|
68
75
|
maxWithdraw(props) {
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
partial: require_onchain_accounts_intents_math.maxProportionalWithdrawal(view, view.debtLimits),
|
|
72
|
-
exit: view.collateral > 0n ? view.collateral : 0n
|
|
73
|
-
};
|
|
76
|
+
return require_onchain_accounts_intents_withdraw_limits.withdrawLimits(props);
|
|
74
77
|
}
|
|
75
78
|
/**
|
|
76
79
|
* Debt a `REPAY` would have to cover to settle the account, in underlying
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_onchain_utils_bigint_math = require("../../utils/bigint-math.js");
|
|
3
|
-
|
|
3
|
+
require("../../constants/math.js");
|
|
4
4
|
require("../../utils/index.js");
|
|
5
5
|
const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
|
|
6
|
+
const require_onchain_accounts_intents_collateral_money = require("./collateral-money.js");
|
|
6
7
|
//#region src/onchain/accounts/intents/maxWithdrawCollateral.ts
|
|
7
8
|
/**
|
|
8
9
|
* Largest amount of one collateral the account can withdraw while its health
|
|
9
10
|
* factor stays at or above `targetHF`.
|
|
10
11
|
*
|
|
11
12
|
* This is the collateral check solved for one balance, and it counts what that
|
|
12
|
-
* check counts
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Collateral is valued at the protocol safe price (`min` of the two feeds,
|
|
16
|
-
* 0 when there is no reserve), the way the facade values a call that hands
|
|
17
|
-
* funds over; the underlying is exempt and is valued at the main feed, as
|
|
18
|
-
* `CreditManagerV3._safeConvertToUSD` does. The debt is valued at the main
|
|
19
|
-
* feed, as the check does. Zero debt frees the whole balance.
|
|
13
|
+
* check counts — see {@link collateralMoney} for the valuation, safe prices
|
|
14
|
+
* included. The debt is valued at the main feed, as the check does. Zero debt
|
|
15
|
+
* frees the whole balance.
|
|
20
16
|
*
|
|
21
17
|
* Rounding always favours the account, so the answer clears the check rather
|
|
22
18
|
* than landing a wei short of it.
|
|
@@ -27,49 +23,27 @@ const require_onchain_accounts_intents_utils_common = require("./utils/common.js
|
|
|
27
23
|
**/
|
|
28
24
|
function maxWithdrawCollateral(props) {
|
|
29
25
|
const { creditAccount, sdk, token, targetHF } = props;
|
|
30
|
-
const { market, creditManager } = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
|
|
31
|
-
const { priceOracle } = market;
|
|
32
|
-
const { pqk } = market.pool;
|
|
33
|
-
const underlying = market.pool.underlying;
|
|
34
26
|
const target = creditAccount.tokens.find((t) => require_onchain_accounts_intents_utils_common.eq(t.token, token));
|
|
35
27
|
if (!target || target.balance <= 10n) return 0n;
|
|
36
28
|
if (creditAccount.totalDebt === 0n) return target.balance;
|
|
37
|
-
const
|
|
38
|
-
const counts = (t) => t.balance > 10n && (!masked || (t.mask & creditAccount.enabledTokensMask) !== 0n);
|
|
39
|
-
/** What a holding backs, in the check's units: USD × PERCENTAGE_FACTOR. */
|
|
40
|
-
const weigh = (t) => {
|
|
41
|
-
const lt = BigInt(creditManager.liquidationThresholds.get(t.token) ?? 0);
|
|
42
|
-
const weighted = (require_onchain_accounts_intents_utils_common.eq(t.token, underlying) ? usd(priceOracle, t.token, t.balance) ?? 0n : priceOracle.safeConvertMinUSD(t.token, t.balance).value) * lt;
|
|
43
|
-
if (t.quota === 0n) return weighted;
|
|
44
|
-
return require_onchain_utils_bigint_math.BigIntMath.min(quotaUsd(t) * require_onchain_constants_math.PERCENTAGE_FACTOR, weighted);
|
|
45
|
-
};
|
|
46
|
-
/** A quota is underlying-denominated, and a closed market backs nothing. */
|
|
47
|
-
const quotaUsd = (t) => pqk.hasActiveQuota(t.token) ? usd(priceOracle, underlying, t.quota) ?? 0n : 0n;
|
|
29
|
+
const money = require_onchain_accounts_intents_collateral_money.collateralMoney(creditAccount, sdk);
|
|
48
30
|
let otherMoney = 0n;
|
|
49
31
|
for (const t of creditAccount.tokens) {
|
|
50
|
-
if (require_onchain_accounts_intents_utils_common.eq(t.token, token) || !counts(t)) continue;
|
|
51
|
-
otherMoney += weigh(t);
|
|
32
|
+
if (require_onchain_accounts_intents_utils_common.eq(t.token, token) || !money.counts(t)) continue;
|
|
33
|
+
otherMoney += money.weigh(t);
|
|
52
34
|
}
|
|
53
|
-
const borrowed =
|
|
35
|
+
const borrowed = money.mainUsd(money.underlying, creditAccount.totalDebt);
|
|
54
36
|
if (borrowed === void 0 || borrowed <= 0n) return 0n;
|
|
55
37
|
const required = borrowed * targetHF;
|
|
56
38
|
if (required <= otherMoney) return target.balance;
|
|
57
39
|
const shortfall = required - otherMoney;
|
|
58
|
-
if (target.quota > 0n &&
|
|
59
|
-
const targetLt =
|
|
60
|
-
const targetUsd =
|
|
40
|
+
if (target.quota > 0n && money.quotaMoney(target) < shortfall) return 0n;
|
|
41
|
+
const targetLt = money.lt(target.token);
|
|
42
|
+
const targetUsd = money.checkedUsd(target);
|
|
61
43
|
if (targetLt === 0n || targetUsd === 0n) return 0n;
|
|
62
44
|
const keptUsd = require_onchain_utils_bigint_math.BigIntMath.ceilDiv(shortfall, targetLt);
|
|
63
45
|
const kept = require_onchain_utils_bigint_math.BigIntMath.ceilDiv(target.balance * keptUsd, targetUsd);
|
|
64
46
|
return kept >= target.balance ? 0n : target.balance - kept;
|
|
65
47
|
}
|
|
66
|
-
/** USD value at the main feed, or `undefined` when the token has no price. */
|
|
67
|
-
function usd(oracle, token, amount) {
|
|
68
|
-
try {
|
|
69
|
-
return oracle.convertToUSD(token, amount);
|
|
70
|
-
} catch {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
48
|
//#endregion
|
|
75
49
|
exports.maxWithdrawCollateral = maxWithdrawCollateral;
|
|
@@ -12,6 +12,7 @@ const require_onchain_accounts_intents_utils_price_impact = require("./utils/pri
|
|
|
12
12
|
const require_onchain_accounts_intents_utils_quotas_for_update = require("./utils/quotas-for-update.js");
|
|
13
13
|
const require_onchain_accounts_intents_utils_router_path = require("./utils/router-path.js");
|
|
14
14
|
const require_onchain_accounts_intents_operations = require("./operations.js");
|
|
15
|
+
const require_onchain_accounts_intents_withdraw_limits = require("./withdraw-limits.js");
|
|
15
16
|
//#region src/onchain/accounts/intents/realize.ts
|
|
16
17
|
/**
|
|
17
18
|
* Turns a plan into operations: the one place that talks to the router, knows
|
|
@@ -320,11 +321,18 @@ async function realize(steps, props) {
|
|
|
320
321
|
totalValue: projected.totalValue
|
|
321
322
|
};
|
|
322
323
|
const projection = sdk.positions.projection(snapshot, { availableLiquidityChange: creditAccount.totalDebt - debt });
|
|
323
|
-
|
|
324
|
+
const settled = {
|
|
324
325
|
...snapshot,
|
|
325
326
|
assets,
|
|
326
327
|
totalValue: floor.totalValue
|
|
327
|
-
}
|
|
328
|
+
};
|
|
329
|
+
require_onchain_accounts_intents_guards.assertCollateralised(sdk.positions.healthFactor(settled, { safePrices: withdrawsCollateral }), withdrawsCollateral, () => ({
|
|
330
|
+
atMainPrices: sdk.positions.healthFactor(settled, { safePrices: false }),
|
|
331
|
+
withdrawable: require_onchain_validation_helpers_token.toTokenAmount(sdk, underlying, require_onchain_accounts_intents_withdraw_limits.withdrawLimits({
|
|
332
|
+
creditAccount,
|
|
333
|
+
sdk
|
|
334
|
+
}).safePartial)
|
|
335
|
+
}));
|
|
328
336
|
const priceImpact = await require_onchain_accounts_intents_utils_price_impact.collectPriceImpact(probes, {
|
|
329
337
|
totalValue: projected.totalValue,
|
|
330
338
|
netValue: projected.totalValue - debt,
|
|
@@ -8,8 +8,8 @@ const require_onchain_accounts_intents_utils_common = require("./utils/common.js
|
|
|
8
8
|
const require_onchain_accounts_intents_utils_router_path = require("./utils/router-path.js");
|
|
9
9
|
const require_onchain_accounts_intents_plan = require("./plan.js");
|
|
10
10
|
const require_onchain_accounts_intents_operations = require("./operations.js");
|
|
11
|
-
const require_onchain_accounts_intents_realize = require("./realize.js");
|
|
12
11
|
const require_onchain_accounts_intents_view = require("./view.js");
|
|
12
|
+
const require_onchain_accounts_intents_realize = require("./realize.js");
|
|
13
13
|
//#region src/onchain/accounts/intents/tail.ts
|
|
14
14
|
/**
|
|
15
15
|
* The second half of a delayed intent: the claim, then whatever the intent
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_onchain_utils_bigint_math = require("../../utils/bigint-math.js");
|
|
3
|
+
require("../../utils/index.js");
|
|
4
|
+
const require_onchain_validation_helpers_health_factor_limits = require("../../validation/helpers/health-factor-limits.js");
|
|
5
|
+
require("../../validation/index.js");
|
|
6
|
+
const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
|
|
7
|
+
const require_onchain_accounts_intents_collateral_money = require("./collateral-money.js");
|
|
8
|
+
const require_onchain_accounts_intents_math = require("./math.js");
|
|
9
|
+
const require_onchain_accounts_intents_view = require("./view.js");
|
|
10
|
+
//#region src/onchain/accounts/intents/withdraw-limits.ts
|
|
11
|
+
/**
|
|
12
|
+
* Every limit a `WITHDRAW` answers to, in underlying units.
|
|
13
|
+
*
|
|
14
|
+
* The one place they are assembled, so the figure a form is offered and the
|
|
15
|
+
* figure the collateral guard names when it turns a withdrawal down cannot
|
|
16
|
+
* drift apart: `CreditAccountOperationsService` reports this, and the guard
|
|
17
|
+
* quotes it back.
|
|
18
|
+
*
|
|
19
|
+
* @param props - Account slice, the SDK holding its market, and optionally the
|
|
20
|
+
* collateral the withdrawal would be funded from
|
|
21
|
+
* @returns The three limits, see {@link WithdrawCeilings}
|
|
22
|
+
**/
|
|
23
|
+
function withdrawLimits(props) {
|
|
24
|
+
const { creditAccount, sdk } = props;
|
|
25
|
+
const view = require_onchain_accounts_intents_view.accountView(creditAccount, sdk);
|
|
26
|
+
const partial = require_onchain_accounts_intents_math.maxProportionalWithdrawal(view, view.debtLimits);
|
|
27
|
+
const safe = maxSafeWithdrawal({
|
|
28
|
+
...props,
|
|
29
|
+
targetHF: BigInt(require_onchain_validation_helpers_health_factor_limits.MIN_HEALTH_FACTOR_FACADE)
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
partial,
|
|
33
|
+
safePartial: require_onchain_utils_bigint_math.BigIntMath.min(partial, safe),
|
|
34
|
+
exit: view.collateral > 0n ? view.collateral : 0n
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Largest proportional withdrawal the safe-price collateral check still clears,
|
|
39
|
+
* in underlying units.
|
|
40
|
+
*
|
|
41
|
+
* A withdrawal hands funds over, so the facade weighs the account it leaves
|
|
42
|
+
* behind at safe prices rather than main ones — see {@link collateralMoney}.
|
|
43
|
+
* That is a second limit on top of the facade's `debtLimits`, and the two are
|
|
44
|
+
* independent: a caller wanting the amount a form may actually offer takes the
|
|
45
|
+
* lesser of this and `maxProportionalWithdrawal`.
|
|
46
|
+
*
|
|
47
|
+
* The arithmetic is the check solved for the amount. Taking `W` out at fixed
|
|
48
|
+
* leverage repays `dD = D·W/C`, so `W·TVL/C` of value is sold out of the source
|
|
49
|
+
* token; each dollar of that sale costs the check the source's threshold times
|
|
50
|
+
* its safe-to-main price ratio, while the repayment relieves `targetHF` per
|
|
51
|
+
* dollar of debt. Both terms are linear in `W`, which is why one division
|
|
52
|
+
* answers instead of a search — and why the answer is exact rather than a
|
|
53
|
+
* bound, as long as the plan really does fund itself from `sourceToken`.
|
|
54
|
+
*
|
|
55
|
+
* Two consequences worth stating, because they surprise:
|
|
56
|
+
*
|
|
57
|
+
* - An account whose collateral is entirely a token the reserve feed marks
|
|
58
|
+
* down cannot withdraw at all once it is under the threshold. A proportional
|
|
59
|
+
* withdrawal scales collateral and debt together, so it leaves the safe-price
|
|
60
|
+
* factor exactly where it found it — no amount climbs back over.
|
|
61
|
+
* - Leaving entirely is never refused for this reason: the exit settles the
|
|
62
|
+
* debt instead of shrinking it, and a check with no debt to divide by has
|
|
63
|
+
* nothing to refuse.
|
|
64
|
+
*
|
|
65
|
+
* @returns Amount in underlying units. The account's net value when safe prices
|
|
66
|
+
* do not limit the withdrawal at all, so the caller's `min` is a no-op; `0n`
|
|
67
|
+
* when the account already sits below `targetHF` at safe prices, and only the
|
|
68
|
+
* exit is left
|
|
69
|
+
**/
|
|
70
|
+
function maxSafeWithdrawal(props) {
|
|
71
|
+
const { creditAccount, sdk, targetHF } = props;
|
|
72
|
+
const view = require_onchain_accounts_intents_view.accountView(creditAccount, sdk);
|
|
73
|
+
if (view.collateral <= 0n) return 0n;
|
|
74
|
+
if (view.debt === 0n) return view.collateral;
|
|
75
|
+
const money = require_onchain_accounts_intents_collateral_money.collateralMoney(creditAccount, sdk);
|
|
76
|
+
const source = props.sourceToken ?? view.fattest();
|
|
77
|
+
const holding = source === void 0 ? void 0 : creditAccount.tokens.find((t) => require_onchain_accounts_intents_utils_common.eq(t.token, source));
|
|
78
|
+
if (!holding) return view.collateral;
|
|
79
|
+
let total = 0n;
|
|
80
|
+
for (const t of creditAccount.tokens) if (money.counts(t)) total += money.weigh(t);
|
|
81
|
+
const debtUsd = money.mainUsd(money.underlying, view.debt);
|
|
82
|
+
if (debtUsd === void 0 || debtUsd <= 0n) return view.collateral;
|
|
83
|
+
const slack = total - debtUsd * targetHF;
|
|
84
|
+
if (slack < 0n) return 0n;
|
|
85
|
+
const sourceMainUsd = money.mainUsd(holding.token, holding.balance);
|
|
86
|
+
if (sourceMainUsd === void 0 || sourceMainUsd <= 0n) return view.collateral;
|
|
87
|
+
const sourceRate = money.lt(holding.token) * money.checkedUsd(holding);
|
|
88
|
+
const tvlUsd = money.mainUsd(money.underlying, view.collateral + view.debt);
|
|
89
|
+
if (tvlUsd === void 0) return view.collateral;
|
|
90
|
+
const drain = sourceRate * tvlUsd - targetHF * debtUsd * sourceMainUsd;
|
|
91
|
+
if (drain <= 0n) return view.collateral;
|
|
92
|
+
const limit = view.collateral * slack * sourceMainUsd / drain;
|
|
93
|
+
return limit < view.collateral ? limit : view.collateral;
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
exports.maxSafeWithdrawal = maxSafeWithdrawal;
|
|
97
|
+
exports.withdrawLimits = withdrawLimits;
|
|
@@ -213,6 +213,7 @@ const require_onchain_validation_checks_checkPoolPaused = require("./validation/
|
|
|
213
213
|
const require_onchain_validation_checks_checkPoolSunset = require("./validation/checks/checkPoolSunset.js");
|
|
214
214
|
const require_onchain_validation_checks_checkQuotaCount = require("./validation/checks/checkQuotaCount.js");
|
|
215
215
|
const require_onchain_validation_checks_checkQuotaLimit = require("./validation/checks/checkQuotaLimit.js");
|
|
216
|
+
const require_onchain_validation_checks_checkReservePriceLimited = require("./validation/checks/checkReservePriceLimited.js");
|
|
216
217
|
const require_onchain_validation_bundles_checkAccountQuotas = require("./validation/bundles/checkAccountQuotas.js");
|
|
217
218
|
const require_onchain_validation_bundles_checkWalletAllowance = require("./validation/bundles/checkWalletAllowance.js");
|
|
218
219
|
const require_onchain_validation_bundles_checkWalletBalance = require("./validation/bundles/checkWalletBalance.js");
|
|
@@ -586,6 +587,7 @@ exports.checkQuotaCount = require_onchain_validation_checks_checkQuotaCount.chec
|
|
|
586
587
|
exports.checkQuotaLimit = require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit;
|
|
587
588
|
exports.checkRWAOpenRequirements = require_onchain_validation_bundles_checkRWAOpenRequirements.checkRWAOpenRequirements;
|
|
588
589
|
exports.checkRWAOpening = require_onchain_validation_bundles_checkRWAOpening.checkRWAOpening;
|
|
590
|
+
exports.checkReservePriceLimited = require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited;
|
|
589
591
|
exports.checkSimulation = require_onchain_validation_checkSimulation.checkSimulation;
|
|
590
592
|
exports.checkWallet = require_onchain_validation_bundles_checkWallet.checkWallet;
|
|
591
593
|
exports.checkWalletAllowance = require_onchain_validation_bundles_checkWalletAllowance.checkWalletAllowance;
|
|
@@ -20,7 +20,7 @@ const adapterConstructorAbi = {
|
|
|
20
20
|
["INFINIFI_GATEWAY"]: { 310: require_onchain_market_adapters_abi_conctructorAbiPatterns.BASIC_ADAPTER_ABI },
|
|
21
21
|
["LIDO_V1"]: { 310: require_onchain_market_adapters_abi_conctructorAbiPatterns.BASIC_ADAPTER_ABI },
|
|
22
22
|
["LIDO_WSTETH_V1"]: { 310: require_onchain_market_adapters_abi_conctructorAbiPatterns.BASIC_ADAPTER_ABI },
|
|
23
|
-
["MIDAS_GATEWAY"]: { 311: require_onchain_market_adapters_abi_conctructorAbiPatterns.
|
|
23
|
+
["MIDAS_GATEWAY"]: { 311: require_onchain_market_adapters_abi_conctructorAbiPatterns.BASIC_ADAPTER_ABI },
|
|
24
24
|
["MIDAS_REDEMPTION_VAULT"]: {
|
|
25
25
|
310: require_onchain_market_adapters_abi_conctructorAbiPatterns.BASIC_ADAPTER_ABI,
|
|
26
26
|
311: require_onchain_market_adapters_abi_conctructorAbiPatterns.BASIC_ADAPTER_ABI
|
|
@@ -3,25 +3,22 @@ const require_onchain_constants_address_provider = require("../../constants/addr
|
|
|
3
3
|
const require_model_previews = require("../../../model/previews.js");
|
|
4
4
|
const require_model_result = require("../../../model/result.js");
|
|
5
5
|
require("../../../model/index.js");
|
|
6
|
-
const require_onchain_preview_preview_CreditAccountState = require("./CreditAccountState.js");
|
|
7
6
|
const require_onchain_preview_preview_unwrapNativeCollateral = require("./unwrapNativeCollateral.js");
|
|
8
|
-
const require_onchain_preview_preview_replayInnerOperations = require("./replayInnerOperations.js");
|
|
9
7
|
//#region src/onchain/preview/preview/previewOpenStrategyPosition.ts
|
|
10
|
-
function previewOpenStrategyPosition(sdk, input, operation) {
|
|
8
|
+
function previewOpenStrategyPosition(sdk, input, operation, replay) {
|
|
11
9
|
const { value = 0n } = input;
|
|
12
10
|
const market = sdk.marketRegister.findByCreditManager(operation.creditManager);
|
|
13
11
|
const oracle = market.priceOracle;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
if (replayError) return require_model_result.sdkErr(replayError);
|
|
17
|
-
const account = state.account;
|
|
12
|
+
const { before, after } = replay;
|
|
13
|
+
const account = after.account;
|
|
18
14
|
let warning;
|
|
19
|
-
const
|
|
15
|
+
const price = (token, balance) => {
|
|
20
16
|
const priced = oracle.safeConvert(token, market.underlying, balance);
|
|
21
17
|
warning ??= priced.error;
|
|
22
18
|
return priced.value;
|
|
23
|
-
}
|
|
24
|
-
const
|
|
19
|
+
};
|
|
20
|
+
const netValue = before.balances.sum(price) + after.collateralAdded.sum(price);
|
|
21
|
+
const unwrapped = require_onchain_preview_preview_unwrapNativeCollateral.unwrapNativeCollateral(after.collateralAdded.toAssets(), value, sdk.addressProvider.getAddress(require_onchain_constants_address_provider.AP_WETH_TOKEN, 0));
|
|
25
22
|
if (!unwrapped.ok) return unwrapped;
|
|
26
23
|
const collateral = unwrapped.data;
|
|
27
24
|
const snap = account.toSnapshot(netValue + account.totalDebt);
|
|
@@ -32,14 +29,11 @@ function previewOpenStrategyPosition(sdk, input, operation) {
|
|
|
32
29
|
collateralAdded: collateral.map((a) => oracle.toTokenAmount(a.token, a.balance)),
|
|
33
30
|
warning
|
|
34
31
|
};
|
|
35
|
-
if (operation.operation === "RWAOpenCreditAccount") return require_model_result.sdkOk({
|
|
36
|
-
...projection,
|
|
37
|
-
operation: "RWAOpenCreditAccount",
|
|
38
|
-
rwaArgs: operation.args
|
|
39
|
-
});
|
|
40
32
|
return require_model_result.sdkOk({
|
|
41
33
|
...projection,
|
|
42
|
-
operation: "OpenCreditAccount"
|
|
34
|
+
operation: "OpenCreditAccount",
|
|
35
|
+
...operation.operation === "MultiCall" || operation.operation === "BotMulticall" || operation.operation === "RWAMulticall" ? { creditAccount: operation.creditAccount } : {},
|
|
36
|
+
..."args" in operation ? { rwaArgs: operation.args } : {}
|
|
43
37
|
});
|
|
44
38
|
}
|
|
45
39
|
/**
|