@gearbox-protocol/sdk 16.0.0-next.36 → 16.0.0-next.38

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.
Files changed (34) hide show
  1. package/dist/cjs/model/liquidations.schema.js +1 -0
  2. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +12 -1
  3. package/dist/cjs/onchain/market/credit/CreditSuite.js +37 -3
  4. package/dist/cjs/onchain/market/credit/creditOperationMarket.js +3 -2
  5. package/dist/cjs/onchain/positions/PositionsService.js +3 -6
  6. package/dist/cjs/preview/index.js +2 -0
  7. package/dist/cjs/preview/preview/buildDelayedStrategyPositionOperationPreview.js +7 -1
  8. package/dist/cjs/preview/preview/estimateClaimableAt.js +21 -0
  9. package/dist/cjs/preview/preview/index.js +2 -0
  10. package/dist/cjs/preview/preview/previewAdjustStrategyPosition.js +3 -0
  11. package/dist/cjs/preview/preview/previewExitOrRepayStrategyPosition.js +8 -2
  12. package/dist/cjs/preview/preview/previewOperation.js +6 -1
  13. package/dist/cjs/preview/preview/previewPoolPositionOperation.js +1 -0
  14. package/dist/esm/model/liquidations.schema.js +2 -1
  15. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +12 -1
  16. package/dist/esm/onchain/market/credit/CreditSuite.js +38 -4
  17. package/dist/esm/onchain/market/credit/creditOperationMarket.js +3 -2
  18. package/dist/esm/onchain/positions/PositionsService.js +3 -6
  19. package/dist/esm/preview/index.js +2 -1
  20. package/dist/esm/preview/preview/buildDelayedStrategyPositionOperationPreview.js +7 -1
  21. package/dist/esm/preview/preview/estimateClaimableAt.js +20 -0
  22. package/dist/esm/preview/preview/index.js +2 -1
  23. package/dist/esm/preview/preview/previewAdjustStrategyPosition.js +3 -0
  24. package/dist/esm/preview/preview/previewExitOrRepayStrategyPosition.js +8 -2
  25. package/dist/esm/preview/preview/previewOperation.js +6 -1
  26. package/dist/esm/preview/preview/previewPoolPositionOperation.js +1 -0
  27. package/dist/types/model/liquidations.schema.d.ts +18 -0
  28. package/dist/types/model/previews.d.ts +44 -2
  29. package/dist/types/onchain/market/credit/CreditSuite.d.ts +27 -1
  30. package/dist/types/onchain/market/credit/creditOperationMarket.d.ts +1 -1
  31. package/dist/types/preview/index.d.ts +2 -1
  32. package/dist/types/preview/preview/estimateClaimableAt.d.ts +19 -0
  33. package/dist/types/preview/preview/index.d.ts +2 -1
  34. package/package.json +1 -1
@@ -25,6 +25,7 @@ const liquidatableAccountFilterSchema = zod_v4.z.object({
25
25
  const liquidatableAccountSchema = zod_v4.z.object({
26
26
  creditManager: require_onchain_utils_zod.ZodAddress(),
27
27
  name: zod_v4.z.string(),
28
+ underlyingToken: require_model_primitives_schema.underlyingTokenSchema,
28
29
  curator: require_model_curators_schema.curatorSchema,
29
30
  liquidationDiscount: require_model_primitives_schema.bpsSchema,
30
31
  chainId: require_model_primitives_schema.chainIdSchema,
@@ -225,8 +225,19 @@ function buildMockSdk(args) {
225
225
  const forbiddenTokensMask = collateralTokens.reduce((mask, token, i) => forbidden.has(token) ? mask | 1n << BigInt(i) : mask, 0n);
226
226
  const facadePaused = args.facadePaused ?? false;
227
227
  const expirationDate = args.expirationDate ?? 0;
228
+ const strategyTargetCollateral = args.strategyTargetCollateral ?? collateralTokens.find((t) => t !== args.underlying.toLowerCase());
229
+ const unwrappedUnderlying = args.rwaAssets?.[args.underlying.toLowerCase()] ?? args.underlying;
230
+ const underlyingToken = {
231
+ ...tokenOf(unwrappedUnderlying),
232
+ wrappedAddress: unwrappedUnderlying.toLowerCase() === args.underlying.toLowerCase() ? null : args.underlying
233
+ };
234
+ const strategyName = strategyTargetCollateral ? `${tokenOf(strategyTargetCollateral).symbol} / ${underlyingToken.symbol}` : void 0;
228
235
  const creditManagerSuite = {
229
236
  name: "TestCreditManager",
237
+ strategyName,
238
+ underlyingToken,
239
+ accountTargetCollateral: () => strategyTargetCollateral ? tokenOf(strategyTargetCollateral) : null,
240
+ accountStrategyName: () => strategyName ?? underlyingToken.symbol,
230
241
  liquidationFees: () => MOCK_LIQUIDATION_FEES,
231
242
  creditManager: {
232
243
  address: args.creditManager,
@@ -248,7 +259,7 @@ function buildMockSdk(args) {
248
259
  market,
249
260
  isPaused: facadePaused || poolPaused,
250
261
  forbiddenTokens: [...forbidden],
251
- strategyTargetCollateral: args.strategyTargetCollateral ?? collateralTokens.find((t) => t !== args.underlying.toLowerCase()),
262
+ strategyTargetCollateral,
252
263
  isExpired: expirationDate > 0 && expirationDate < (args.timestamp ?? 0)
253
264
  };
254
265
  const routeCalls = (tokenIn, tokenOut) => {
@@ -86,6 +86,16 @@ var CreditSuite = class extends require_onchain_base_SDKConstruct.SDKConstruct {
86
86
  return this.creditManager.underlying;
87
87
  }
88
88
  /**
89
+ * Pool underlying token as the shared read model describes it.
90
+ *
91
+ * For RWA markets this is the unwrapped asset, e.g. USDC rather than
92
+ * dcUSDC (the pool's on-chain underlying). Same as
93
+ * {@link MarketSuite.underlyingToken}.
94
+ */
95
+ get underlyingToken() {
96
+ return this.market.underlyingToken;
97
+ }
98
+ /**
89
99
  * Parent market that contains this credit manager
90
100
  */
91
101
  get market() {
@@ -222,7 +232,31 @@ var CreditSuite = class extends require_onchain_base_SDKConstruct.SDKConstruct {
222
232
  get strategyName() {
223
233
  const collateral = this.strategyTargetCollateral;
224
234
  if (!collateral) return;
225
- return require_onchain_market_strategyName.strategyName(this.tokensMeta.mustGetToken(collateral), this.market.underlyingToken);
235
+ return require_onchain_market_strategyName.strategyName(this.tokensMeta.mustGetToken(collateral), this.underlyingToken);
236
+ }
237
+ /**
238
+ * Collateral token an existing credit account in this suite is a strategy
239
+ * in. Same as {@link StrategyPosition.targetCollateral}.
240
+ *
241
+ * Resolution, in order:
242
+ * 1. a hardcoded per-account override, when present;
243
+ * 2. {@link strategyTargetCollateral};
244
+ * 3. `null` when neither can be resolved.
245
+ */
246
+ accountTargetCollateral(creditAccount) {
247
+ const addr = require_onchain_chain_chains.getAccountTargetCollateral(creditAccount, this.chainId) ?? this.strategyTargetCollateral;
248
+ return addr ? this.tokensMeta.mustGetToken(addr) : null;
249
+ }
250
+ /**
251
+ * Display name of an existing credit account in this suite, e.g.
252
+ * `"wstETH / WETH"`. Same as {@link StrategyPosition.name}.
253
+ *
254
+ * {@link accountTargetCollateral} over the underlying, or the underlying
255
+ * symbol when no target can be resolved.
256
+ */
257
+ accountStrategyName(creditAccount) {
258
+ const target = this.accountTargetCollateral(creditAccount);
259
+ return target ? require_onchain_market_strategyName.strategyName(target, this.underlyingToken) : this.underlyingToken.symbol;
226
260
  }
227
261
  /**
228
262
  * Describes this suite's leveraged strategy as the shared read model does,
@@ -245,9 +279,9 @@ var CreditSuite = class extends require_onchain_base_SDKConstruct.SDKConstruct {
245
279
  chainId: this.chainId,
246
280
  creditManager: cm.address,
247
281
  targetCollateral: this.tokensMeta.mustGetToken(collateral),
248
- name: this.strategyName ?? this.market.underlyingToken.symbol,
282
+ name: this.strategyName ?? this.underlyingToken.symbol,
249
283
  curator: market.curator,
250
- underlyingToken: market.underlyingToken,
284
+ underlyingToken: this.underlyingToken,
251
285
  totalBorrowed: oracle.toAmount(pool.underlying, borrowed),
252
286
  allowedDepositTokens: this.#allowedDepositTokens(collateral),
253
287
  paused: this.isPaused,
@@ -17,7 +17,7 @@ function totalLiquidationDiscount(suite) {
17
17
  /**
18
18
  * The market half of every credit operation result, read off the suite that
19
19
  * serves it: a preview, a projection, the open-strategy walk and a
20
- * liquidatable-account row all spread it, so the four fields are filled in one
20
+ * liquidatable-account row all spread it, so the five fields are filled in one
21
21
  * place and cannot drift apart between the halves of the SDK.
22
22
  *
23
23
  * The curator comes from the same getter {@link CreditSuite.strategyOpportunity}
@@ -26,7 +26,8 @@ function totalLiquidationDiscount(suite) {
26
26
  function creditOperationMarket(suite) {
27
27
  return {
28
28
  creditManager: suite.creditManager.address,
29
- name: suite.name,
29
+ name: suite.strategyName ?? suite.underlyingToken.symbol,
30
+ underlyingToken: suite.underlyingToken,
30
31
  curator: suite.market.curator,
31
32
  liquidationDiscount: totalLiquidationDiscount(suite)
32
33
  };
@@ -1,13 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_utils_AddressMap = require("../utils/AddressMap.js");
3
- const require_onchain_chain_chains = require("../chain/chains.js");
4
3
  require("../constants/math.js");
5
4
  require("../constants/index.js");
6
5
  require("../utils/index.js");
7
6
  const require_onchain_base_SDKConstruct = require("../base/SDKConstruct.js");
8
7
  require("../base/index.js");
9
8
  const require_onchain_market_math = require("../market/math.js");
10
- const require_onchain_market_strategyName = require("../market/strategyName.js");
11
9
  const require_onchain_market_credit_creditOperationMarket = require("../market/credit/creditOperationMarket.js");
12
10
  const require_model_filters = require("../../model/filters.js");
13
11
  const require_model_positions = require("../../model/positions.js");
@@ -287,9 +285,8 @@ var PositionsService = class extends require_onchain_base_SDKConstruct.SDKConstr
287
285
  const { market } = suite;
288
286
  const { priceOracle } = market;
289
287
  const { pool } = market.pool;
290
- const token = market.underlyingToken;
288
+ const token = suite.underlyingToken;
291
289
  const totalDebtValue = ca.debt + ca.accruedInterest + ca.accruedFees;
292
- const target = require_onchain_chain_chains.getAccountTargetCollateral(ca.creditAccount, this.sdk.chainId) ?? suite.strategyTargetCollateral;
293
290
  const priceFailed = !ca.success;
294
291
  const recomputeTotals = ca.debt === 0n || priceFailed;
295
292
  const collaterals = [];
@@ -323,8 +320,8 @@ var PositionsService = class extends require_onchain_base_SDKConstruct.SDKConstr
323
320
  creditManager: ca.creditManager,
324
321
  creditAccount: ca.creditAccount,
325
322
  underlyingToken: token,
326
- name: target ? require_onchain_market_strategyName.strategyName(this.sdk.tokensMeta.mustGetToken(target), token) : token.symbol,
327
- targetCollateral: target ? this.sdk.tokensMeta.mustGetToken(target) : null,
323
+ name: suite.accountStrategyName(ca.creditAccount),
324
+ targetCollateral: suite.accountTargetCollateral(ca.creditAccount),
328
325
  leverage: require_onchain_market_math.calcPositionLeverage(totalValue, totalDebtValue),
329
326
  borrowApy: require_onchain_market_math.calcBorrowApy(pool.baseInterestRate, suite.creditManager.feeInterest),
330
327
  totalDebt: {
@@ -26,6 +26,7 @@ const require_preview_preview_detectCloseOrRepay = require("./preview/detectClos
26
26
  const require_preview_preview_detectDelayedClaim = require("./preview/detectDelayedClaim.js");
27
27
  const require_preview_preview_detectDelayedOperation = require("./preview/detectDelayedOperation.js");
28
28
  const require_preview_preview_errors = require("./preview/errors.js");
29
+ const require_preview_preview_estimateClaimableAt = require("./preview/estimateClaimableAt.js");
29
30
  const require_preview_preview_replayInnerOperations = require("./preview/replayInnerOperations.js");
30
31
  const require_preview_preview_replayMulticall = require("./preview/replayMulticall.js");
31
32
  const require_preview_preview_previewAdjustStrategyPosition = require("./preview/previewAdjustStrategyPosition.js");
@@ -60,6 +61,7 @@ exports.classifyInnerOperations = require_preview_parse_classifyInnerOperations.
60
61
  exports.collateralIssue = require_preview_validate_checkOperation.collateralIssue;
61
62
  exports.detectDelayedClaim = require_preview_preview_detectDelayedClaim.detectDelayedClaim;
62
63
  exports.detectDelayedOperation = require_preview_preview_detectDelayedOperation.detectDelayedOperation;
64
+ exports.estimateClaimableAt = require_preview_preview_estimateClaimableAt.estimateClaimableAt;
63
65
  exports.extractAdapterCallTraces = require_preview_trace_extractAdapterCallTraces.extractAdapterCallTraces;
64
66
  exports.extractTransfers = require_preview_trace_extractTransfers.extractTransfers;
65
67
  exports.findFacadeCalls = require_preview_trace_findFacadeCalls.findFacadeCalls;
@@ -164,11 +164,14 @@ function totalValueInUnderlying(post, convert, dust) {
164
164
  function buildClosePreview(post, converter, receivedToken, sdk) {
165
165
  const totalValue = totalValueInUnderlying(post, converter.convert, 0n);
166
166
  const oracle = sdk.marketRegister.findByCreditManager(post.creditManager).priceOracle;
167
+ const suite = sdk.marketRegister.findCreditManager(post.creditManager);
167
168
  return {
168
169
  operation: "CloseCreditAccount",
169
170
  permanent: false,
170
- ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(sdk.marketRegister.findCreditManager(post.creditManager)),
171
+ ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(suite),
171
172
  creditAccount: post.creditAccount,
173
+ name: suite.accountStrategyName(post.creditAccount),
174
+ targetCollateral: suite.accountTargetCollateral(post.creditAccount),
172
175
  receivedAmount: oracle.toTokenAmount(receivedToken, require_onchain_utils_bigint_math.BigIntMath.max(totalValue - post.totalDebt, 0n)),
173
176
  error: converter.error
174
177
  };
@@ -176,11 +179,14 @@ function buildClosePreview(post, converter, receivedToken, sdk) {
176
179
  function buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk) {
177
180
  const snap = post.toSnapshot(totalValueInUnderlying(post, converter.convert, require_onchain_constants_math.DUST_THRESHOLD));
178
181
  const market = sdk.marketRegister.findByCreditManager(post.creditManager);
182
+ const suite = sdk.marketRegister.findCreditManager(post.creditManager);
179
183
  const oracle = market.priceOracle;
180
184
  return {
181
185
  operation: "AdjustCreditAccount",
182
186
  ...require_model_previews.asEstimated(sdk.positions.projection(snap, { availableLiquidityChange: before.totalDebt - post.totalDebt })),
183
187
  creditAccount: post.creditAccount,
188
+ name: suite.accountStrategyName(post.creditAccount),
189
+ targetCollateral: suite.accountTargetCollateral(post.creditAccount),
184
190
  collateralAdded: [],
185
191
  collateralWithdrawn: collateralWithdrawn.toAssets().map((a) => oracle.toTokenAmount(a.token, a.balance)),
186
192
  totalDebtChange: market.toUnderlyingAmount(post.totalDebt - before.totalDebt),
@@ -0,0 +1,21 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let viem = require("viem");
3
+ //#region src/preview/preview/estimateClaimableAt.ts
4
+ /**
5
+ * Estimates when a newly requested delayed withdrawal becomes claimable:
6
+ * `now + withdrawalLength` of the cached withdrawable asset whose phantom
7
+ * token matches `phantomToken`. Same formula as
8
+ * `getWithdrawalRequestResult().claimableAt`.
9
+ *
10
+ * Returns `undefined` when the withdrawal compressor is missing, its assets
11
+ * cache is not loaded, or no asset matches the phantom token.
12
+ */
13
+ function estimateClaimableAt(sdk, phantomToken) {
14
+ const compressor = sdk.withdrawalCompressor;
15
+ if (!compressor?.state) return;
16
+ const asset = compressor.getWithdrawableAssets().find((a) => (0, viem.isAddressEqual)(a.withdrawalPhantomToken, phantomToken));
17
+ if (!asset) return;
18
+ return Math.floor(Date.now() / 1e3) + Number(asset.withdrawalLength);
19
+ }
20
+ //#endregion
21
+ exports.estimateClaimableAt = estimateClaimableAt;
@@ -5,6 +5,7 @@ const require_preview_preview_detectCloseOrRepay = require("./detectCloseOrRepay
5
5
  const require_preview_preview_detectDelayedClaim = require("./detectDelayedClaim.js");
6
6
  const require_preview_preview_detectDelayedOperation = require("./detectDelayedOperation.js");
7
7
  const require_preview_preview_errors = require("./errors.js");
8
+ const require_preview_preview_estimateClaimableAt = require("./estimateClaimableAt.js");
8
9
  const require_preview_preview_replayInnerOperations = require("./replayInnerOperations.js");
9
10
  const require_preview_preview_replayMulticall = require("./replayMulticall.js");
10
11
  const require_preview_preview_previewAdjustStrategyPosition = require("./previewAdjustStrategyPosition.js");
@@ -16,6 +17,7 @@ exports.buildDelayedStrategyPositionOperationPreview = require_preview_preview_b
16
17
  exports.classifyCloseOrRepay = require_preview_preview_detectCloseOrRepay.classifyCloseOrRepay;
17
18
  exports.detectDelayedClaim = require_preview_preview_detectDelayedClaim.detectDelayedClaim;
18
19
  exports.detectDelayedOperation = require_preview_preview_detectDelayedOperation.detectDelayedOperation;
20
+ exports.estimateClaimableAt = require_preview_preview_estimateClaimableAt.estimateClaimableAt;
19
21
  exports.isCloseOrRepay = require_preview_preview_detectCloseOrRepay.isCloseOrRepay;
20
22
  exports.makeReplayState = require_preview_preview_replayInnerOperations.makeReplayState;
21
23
  exports.previewAdjustStrategyPosition = require_preview_preview_previewAdjustStrategyPosition.previewAdjustStrategyPosition;
@@ -17,6 +17,7 @@ const require_preview_preview_unwrapNativeCollateral = require("./unwrapNativeCo
17
17
  function previewAdjustStrategyPosition(input, operation, options) {
18
18
  const { sdk, value = 0n } = input;
19
19
  const market = sdk.marketRegister.findByCreditManager(operation.creditManager);
20
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
20
21
  const oracle = market.priceOracle;
21
22
  const { before, after, error: replayError } = require_preview_preview_replayMulticall.replayMulticall(sdk, operation, options);
22
23
  const account = after.account;
@@ -40,6 +41,8 @@ function previewAdjustStrategyPosition(input, operation, options) {
40
41
  operation: "AdjustCreditAccount",
41
42
  ...require_model_previews.asEstimated(sdk.positions.projection(snap, { availableLiquidityChange: before.totalDebt - account.totalDebt })),
42
43
  creditAccount: operation.creditAccount,
44
+ name: suite.accountStrategyName(operation.creditAccount),
45
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
43
46
  collateralAdded: collateralAdded.map((a) => oracle.toTokenAmount(a.token, a.balance)),
44
47
  collateralWithdrawn: after.collateralWithdrawn.toAssets().map((a) => oracle.toTokenAmount(a.token, a.balance)),
45
48
  totalDebtChange: market.toUnderlyingAmount(account.totalDebt - before.totalDebt),
@@ -25,6 +25,7 @@ function previewCloseCreditAccount(input, operation, permanent, replay) {
25
25
  const { sdk } = input;
26
26
  const market = sdk.marketRegister.findByCreditManager(operation.creditManager);
27
27
  const { after, error } = replay;
28
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
28
29
  let receivedToken = market.underlying;
29
30
  for (const m of operation.multicall) if (m.operation === "WithdrawCollateral" && m.amount === 115792089237316195423570985008687907853269984665640564039457584007913129639935n) {
30
31
  receivedToken = m.token;
@@ -33,8 +34,10 @@ function previewCloseCreditAccount(input, operation, permanent, replay) {
33
34
  return {
34
35
  operation: "CloseCreditAccount",
35
36
  permanent,
36
- ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(sdk.marketRegister.findCreditManager(operation.creditManager)),
37
+ ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(suite),
37
38
  creditAccount: operation.creditAccount,
39
+ name: suite.accountStrategyName(operation.creditAccount),
40
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
38
41
  receivedAmount: market.priceOracle.toTokenAmount(receivedToken, after.collateralWithdrawn.getOrZero(receivedToken)),
39
42
  error
40
43
  };
@@ -50,11 +53,14 @@ function previewRepayCreditAccount(input, operation, permanent, replay) {
50
53
  const { before, after, error: replayError } = replay;
51
54
  const { assets: collateralAdded, error: unwrapError } = require_preview_preview_unwrapNativeCollateral.unwrapNativeCollateral(after.collateralAdded.toAssets(), value, sdk.addressProvider.getAddress(require_onchain_constants_address_provider.AP_WETH_TOKEN, 0));
52
55
  const error = replayError ?? unwrapError;
56
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
53
57
  return {
54
58
  operation: "RepayCreditAccount",
55
59
  permanent,
56
- ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(sdk.marketRegister.findCreditManager(operation.creditManager)),
60
+ ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(suite),
57
61
  creditAccount: operation.creditAccount,
62
+ name: suite.accountStrategyName(operation.creditAccount),
63
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
58
64
  collateralAdded: collateralAdded.map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
59
65
  debtRepaid: market.toUnderlyingAmount(before.totalDebt - after.account.totalDebt),
60
66
  collateralWithdrawn: after.collateralWithdrawn.toAssets().map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
@@ -9,6 +9,7 @@ const require_preview_preview_detectCloseOrRepay = require("./detectCloseOrRepay
9
9
  const require_preview_preview_detectDelayedClaim = require("./detectDelayedClaim.js");
10
10
  const require_preview_preview_detectDelayedOperation = require("./detectDelayedOperation.js");
11
11
  const require_preview_preview_errors = require("./errors.js");
12
+ const require_preview_preview_estimateClaimableAt = require("./estimateClaimableAt.js");
12
13
  const require_preview_preview_replayMulticall = require("./replayMulticall.js");
13
14
  const require_preview_preview_previewAdjustStrategyPosition = require("./previewAdjustStrategyPosition.js");
14
15
  const require_preview_preview_previewExitOrRepayStrategyPosition = require("./previewExitOrRepayStrategyPosition.js");
@@ -66,11 +67,15 @@ async function previewMulticallOperation(input, operation, options) {
66
67
  const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
67
68
  const meta = sdk.tokensMeta.get(market.underlying);
68
69
  const receivedToken = meta && sdk.tokensMeta.isRWAUnderlying(meta) ? meta.asset : market.underlying;
70
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
69
71
  return {
70
72
  operation: "DelayedCreditAccountOperation",
71
73
  creditAccount: operation.creditAccount,
72
- ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(sdk.marketRegister.findCreditManager(operation.creditManager)),
74
+ ...require_onchain_market_credit_creditOperationMarket.creditOperationMarket(suite),
75
+ name: suite.accountStrategyName(operation.creditAccount),
76
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
73
77
  intent: delayed.intent,
78
+ estClaimableAt: require_preview_preview_estimateClaimableAt.estimateClaimableAt(sdk, delayed.request.phantomToken),
74
79
  instantPreview,
75
80
  delayedPreview: require_preview_preview_buildDelayedStrategyPositionOperationPreview.buildDelayedStrategyPositionOperationPreview(after.account, before, delayed, convert, receivedToken, sdk)
76
81
  };
@@ -16,6 +16,7 @@ async function previewPoolPositionOperation(input, operation, options) {
16
16
  operation: operation.operation,
17
17
  pool: operation.pool,
18
18
  name: sdk.tokensMeta.mustGetToken(operation.pool).name,
19
+ underlyingToken: market.underlyingToken,
19
20
  shareRate: market.pool.pool.dieselRate,
20
21
  tokenIn: market.priceOracle.toTokenAmount(tokenIn, sim.amountIn),
21
22
  tokenOut: market.priceOracle.toTokenAmount(tokenOut, sim.amountOut)
@@ -1,5 +1,5 @@
1
1
  import { ZodAddress } from "../onchain/utils/zod.js";
2
- import { assetTypeSchema, bpsSchema, chainIdSchema, timestampSchema, tokenAmountSchema, tokenSchema, txCallSchema } from "./primitives.schema.js";
2
+ import { assetTypeSchema, bpsSchema, chainIdSchema, timestampSchema, tokenAmountSchema, tokenSchema, txCallSchema, underlyingTokenSchema } from "./primitives.schema.js";
3
3
  import { curatorSchema } from "./curators.schema.js";
4
4
  import { filterable } from "./filters.schema.js";
5
5
  import { z } from "zod/v4";
@@ -24,6 +24,7 @@ const liquidatableAccountFilterSchema = z.object({
24
24
  const liquidatableAccountSchema = z.object({
25
25
  creditManager: ZodAddress(),
26
26
  name: z.string(),
27
+ underlyingToken: underlyingTokenSchema,
27
28
  curator: curatorSchema,
28
29
  liquidationDiscount: bpsSchema,
29
30
  chainId: chainIdSchema,
@@ -225,8 +225,19 @@ function buildMockSdk(args) {
225
225
  const forbiddenTokensMask = collateralTokens.reduce((mask, token, i) => forbidden.has(token) ? mask | 1n << BigInt(i) : mask, 0n);
226
226
  const facadePaused = args.facadePaused ?? false;
227
227
  const expirationDate = args.expirationDate ?? 0;
228
+ const strategyTargetCollateral = args.strategyTargetCollateral ?? collateralTokens.find((t) => t !== args.underlying.toLowerCase());
229
+ const unwrappedUnderlying = args.rwaAssets?.[args.underlying.toLowerCase()] ?? args.underlying;
230
+ const underlyingToken = {
231
+ ...tokenOf(unwrappedUnderlying),
232
+ wrappedAddress: unwrappedUnderlying.toLowerCase() === args.underlying.toLowerCase() ? null : args.underlying
233
+ };
234
+ const strategyName = strategyTargetCollateral ? `${tokenOf(strategyTargetCollateral).symbol} / ${underlyingToken.symbol}` : void 0;
228
235
  const creditManagerSuite = {
229
236
  name: "TestCreditManager",
237
+ strategyName,
238
+ underlyingToken,
239
+ accountTargetCollateral: () => strategyTargetCollateral ? tokenOf(strategyTargetCollateral) : null,
240
+ accountStrategyName: () => strategyName ?? underlyingToken.symbol,
230
241
  liquidationFees: () => MOCK_LIQUIDATION_FEES,
231
242
  creditManager: {
232
243
  address: args.creditManager,
@@ -248,7 +259,7 @@ function buildMockSdk(args) {
248
259
  market,
249
260
  isPaused: facadePaused || poolPaused,
250
261
  forbiddenTokens: [...forbidden],
251
- strategyTargetCollateral: args.strategyTargetCollateral ?? collateralTokens.find((t) => t !== args.underlying.toLowerCase()),
262
+ strategyTargetCollateral,
252
263
  isExpired: expirationDate > 0 && expirationDate < (args.timestamp ?? 0)
253
264
  };
254
265
  const routeCalls = (tokenIn, tokenOut) => {
@@ -1,6 +1,6 @@
1
1
  import { AddressMap } from "../../utils/AddressMap.js";
2
2
  import { BigIntMath } from "../../utils/bigint-math.js";
3
- import { getLegacyStrategyTarget, isSunsetStrategy } from "../../chain/chains.js";
3
+ import { getAccountTargetCollateral, getLegacyStrategyTarget, isSunsetStrategy } from "../../chain/chains.js";
4
4
  import { PERCENTAGE_FACTOR, RAY } from "../../constants/math.js";
5
5
  import "../../constants/index.js";
6
6
  import "../../utils/index.js";
@@ -85,6 +85,16 @@ var CreditSuite = class extends SDKConstruct {
85
85
  return this.creditManager.underlying;
86
86
  }
87
87
  /**
88
+ * Pool underlying token as the shared read model describes it.
89
+ *
90
+ * For RWA markets this is the unwrapped asset, e.g. USDC rather than
91
+ * dcUSDC (the pool's on-chain underlying). Same as
92
+ * {@link MarketSuite.underlyingToken}.
93
+ */
94
+ get underlyingToken() {
95
+ return this.market.underlyingToken;
96
+ }
97
+ /**
88
98
  * Parent market that contains this credit manager
89
99
  */
90
100
  get market() {
@@ -221,7 +231,31 @@ var CreditSuite = class extends SDKConstruct {
221
231
  get strategyName() {
222
232
  const collateral = this.strategyTargetCollateral;
223
233
  if (!collateral) return;
224
- return strategyName(this.tokensMeta.mustGetToken(collateral), this.market.underlyingToken);
234
+ return strategyName(this.tokensMeta.mustGetToken(collateral), this.underlyingToken);
235
+ }
236
+ /**
237
+ * Collateral token an existing credit account in this suite is a strategy
238
+ * in. Same as {@link StrategyPosition.targetCollateral}.
239
+ *
240
+ * Resolution, in order:
241
+ * 1. a hardcoded per-account override, when present;
242
+ * 2. {@link strategyTargetCollateral};
243
+ * 3. `null` when neither can be resolved.
244
+ */
245
+ accountTargetCollateral(creditAccount) {
246
+ const addr = getAccountTargetCollateral(creditAccount, this.chainId) ?? this.strategyTargetCollateral;
247
+ return addr ? this.tokensMeta.mustGetToken(addr) : null;
248
+ }
249
+ /**
250
+ * Display name of an existing credit account in this suite, e.g.
251
+ * `"wstETH / WETH"`. Same as {@link StrategyPosition.name}.
252
+ *
253
+ * {@link accountTargetCollateral} over the underlying, or the underlying
254
+ * symbol when no target can be resolved.
255
+ */
256
+ accountStrategyName(creditAccount) {
257
+ const target = this.accountTargetCollateral(creditAccount);
258
+ return target ? strategyName(target, this.underlyingToken) : this.underlyingToken.symbol;
225
259
  }
226
260
  /**
227
261
  * Describes this suite's leveraged strategy as the shared read model does,
@@ -244,9 +278,9 @@ var CreditSuite = class extends SDKConstruct {
244
278
  chainId: this.chainId,
245
279
  creditManager: cm.address,
246
280
  targetCollateral: this.tokensMeta.mustGetToken(collateral),
247
- name: this.strategyName ?? this.market.underlyingToken.symbol,
281
+ name: this.strategyName ?? this.underlyingToken.symbol,
248
282
  curator: market.curator,
249
- underlyingToken: market.underlyingToken,
283
+ underlyingToken: this.underlyingToken,
250
284
  totalBorrowed: oracle.toAmount(pool.underlying, borrowed),
251
285
  allowedDepositTokens: this.#allowedDepositTokens(collateral),
252
286
  paused: this.isPaused,
@@ -16,7 +16,7 @@ function totalLiquidationDiscount(suite) {
16
16
  /**
17
17
  * The market half of every credit operation result, read off the suite that
18
18
  * serves it: a preview, a projection, the open-strategy walk and a
19
- * liquidatable-account row all spread it, so the four fields are filled in one
19
+ * liquidatable-account row all spread it, so the five fields are filled in one
20
20
  * place and cannot drift apart between the halves of the SDK.
21
21
  *
22
22
  * The curator comes from the same getter {@link CreditSuite.strategyOpportunity}
@@ -25,7 +25,8 @@ function totalLiquidationDiscount(suite) {
25
25
  function creditOperationMarket(suite) {
26
26
  return {
27
27
  creditManager: suite.creditManager.address,
28
- name: suite.name,
28
+ name: suite.strategyName ?? suite.underlyingToken.symbol,
29
+ underlyingToken: suite.underlyingToken,
29
30
  curator: suite.market.curator,
30
31
  liquidationDiscount: totalLiquidationDiscount(suite)
31
32
  };
@@ -1,12 +1,10 @@
1
1
  import { AddressMap } from "../utils/AddressMap.js";
2
- import { getAccountTargetCollateral } from "../chain/chains.js";
3
2
  import "../constants/math.js";
4
3
  import "../constants/index.js";
5
4
  import "../utils/index.js";
6
5
  import { SDKConstruct } from "../base/SDKConstruct.js";
7
6
  import "../base/index.js";
8
7
  import { bpsToRay, calcBorrowApy, calcPositionLeverage, healthFactorBps, usdToNumber } from "../market/math.js";
9
- import { strategyName } from "../market/strategyName.js";
10
8
  import { creditOperationMarket } from "../market/credit/creditOperationMarket.js";
11
9
  import { isFilterSet } from "../../model/filters.js";
12
10
  import { STRATEGY_POSITION_COLLATERAL_ERROR, matchesPositionFilter } from "../../model/positions.js";
@@ -286,9 +284,8 @@ var PositionsService = class extends SDKConstruct {
286
284
  const { market } = suite;
287
285
  const { priceOracle } = market;
288
286
  const { pool } = market.pool;
289
- const token = market.underlyingToken;
287
+ const token = suite.underlyingToken;
290
288
  const totalDebtValue = ca.debt + ca.accruedInterest + ca.accruedFees;
291
- const target = getAccountTargetCollateral(ca.creditAccount, this.sdk.chainId) ?? suite.strategyTargetCollateral;
292
289
  const priceFailed = !ca.success;
293
290
  const recomputeTotals = ca.debt === 0n || priceFailed;
294
291
  const collaterals = [];
@@ -322,8 +319,8 @@ var PositionsService = class extends SDKConstruct {
322
319
  creditManager: ca.creditManager,
323
320
  creditAccount: ca.creditAccount,
324
321
  underlyingToken: token,
325
- name: target ? strategyName(this.sdk.tokensMeta.mustGetToken(target), token) : token.symbol,
326
- targetCollateral: target ? this.sdk.tokensMeta.mustGetToken(target) : null,
322
+ name: suite.accountStrategyName(ca.creditAccount),
323
+ targetCollateral: suite.accountTargetCollateral(ca.creditAccount),
327
324
  leverage: calcPositionLeverage(totalValue, totalDebtValue),
328
325
  borrowApy: calcBorrowApy(pool.baseInterestRate, suite.creditManager.feeInterest),
329
326
  totalDebt: {
@@ -25,6 +25,7 @@ import { classifyCloseOrRepay, isCloseOrRepay } from "./preview/detectCloseOrRep
25
25
  import { detectDelayedClaim, resolveDelayedClaimIntent } from "./preview/detectDelayedClaim.js";
26
26
  import { detectDelayedOperation } from "./preview/detectDelayedOperation.js";
27
27
  import { UnsupportedOperationError } from "./preview/errors.js";
28
+ import { estimateClaimableAt } from "./preview/estimateClaimableAt.js";
28
29
  import { makeReplayState, replayInnerOperations } from "./preview/replayInnerOperations.js";
29
30
  import { replayMulticall } from "./preview/replayMulticall.js";
30
31
  import { previewAdjustStrategyPosition } from "./preview/previewAdjustStrategyPosition.js";
@@ -35,4 +36,4 @@ import "./types.js";
35
36
  import { checkOperation, collateralIssue, marketIssues, quotaCountIssue } from "./validate/checkOperation.js";
36
37
  import { checkSimulation } from "./validate/checkSimulation.js";
37
38
  import "./validate/index.js";
38
- export { AllowancePrerequisite, BalancePrerequisite, CreditAccountState, IntentPreviewError, Prerequisite, RWAOpenRequirementsPrerequisite, TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, UnsupportedOperationError, UnsupportedPoolFunctionError, UnsupportedTargetError, UnsupportedZapperFunctionError, WithdrawCollateralAlignmentError, buildDelayedStrategyPositionOperationPreview, checkOperation, checkPrerequisites, checkSimulation, classifyCloseOrRepay, classifyInnerOperations, collateralIssue, detectDelayedClaim, detectDelayedOperation, extractAdapterCallTraces, extractTransfers, findFacadeCalls, isCloseOrRepay, isPoolOperation, isRWAOperation, makeReplayState, marketIssues, parseFacadeOperationCalldata, parseOperationCalldata, parsePoolOperationCalldata, parseRWAFactoryOperationCalldata, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, quotaCountIssue, raise, refuse, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
39
+ export { AllowancePrerequisite, BalancePrerequisite, CreditAccountState, IntentPreviewError, Prerequisite, RWAOpenRequirementsPrerequisite, TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, UnsupportedOperationError, UnsupportedPoolFunctionError, UnsupportedTargetError, UnsupportedZapperFunctionError, WithdrawCollateralAlignmentError, buildDelayedStrategyPositionOperationPreview, checkOperation, checkPrerequisites, checkSimulation, classifyCloseOrRepay, classifyInnerOperations, collateralIssue, detectDelayedClaim, detectDelayedOperation, estimateClaimableAt, extractAdapterCallTraces, extractTransfers, findFacadeCalls, isCloseOrRepay, isPoolOperation, isRWAOperation, makeReplayState, marketIssues, parseFacadeOperationCalldata, parseOperationCalldata, parsePoolOperationCalldata, parseRWAFactoryOperationCalldata, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, quotaCountIssue, raise, refuse, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
@@ -163,11 +163,14 @@ function totalValueInUnderlying(post, convert, dust) {
163
163
  function buildClosePreview(post, converter, receivedToken, sdk) {
164
164
  const totalValue = totalValueInUnderlying(post, converter.convert, 0n);
165
165
  const oracle = sdk.marketRegister.findByCreditManager(post.creditManager).priceOracle;
166
+ const suite = sdk.marketRegister.findCreditManager(post.creditManager);
166
167
  return {
167
168
  operation: "CloseCreditAccount",
168
169
  permanent: false,
169
- ...creditOperationMarket(sdk.marketRegister.findCreditManager(post.creditManager)),
170
+ ...creditOperationMarket(suite),
170
171
  creditAccount: post.creditAccount,
172
+ name: suite.accountStrategyName(post.creditAccount),
173
+ targetCollateral: suite.accountTargetCollateral(post.creditAccount),
171
174
  receivedAmount: oracle.toTokenAmount(receivedToken, BigIntMath.max(totalValue - post.totalDebt, 0n)),
172
175
  error: converter.error
173
176
  };
@@ -175,11 +178,14 @@ function buildClosePreview(post, converter, receivedToken, sdk) {
175
178
  function buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk) {
176
179
  const snap = post.toSnapshot(totalValueInUnderlying(post, converter.convert, DUST_THRESHOLD));
177
180
  const market = sdk.marketRegister.findByCreditManager(post.creditManager);
181
+ const suite = sdk.marketRegister.findCreditManager(post.creditManager);
178
182
  const oracle = market.priceOracle;
179
183
  return {
180
184
  operation: "AdjustCreditAccount",
181
185
  ...asEstimated(sdk.positions.projection(snap, { availableLiquidityChange: before.totalDebt - post.totalDebt })),
182
186
  creditAccount: post.creditAccount,
187
+ name: suite.accountStrategyName(post.creditAccount),
188
+ targetCollateral: suite.accountTargetCollateral(post.creditAccount),
183
189
  collateralAdded: [],
184
190
  collateralWithdrawn: collateralWithdrawn.toAssets().map((a) => oracle.toTokenAmount(a.token, a.balance)),
185
191
  totalDebtChange: market.toUnderlyingAmount(post.totalDebt - before.totalDebt),
@@ -0,0 +1,20 @@
1
+ import { isAddressEqual } from "viem";
2
+ //#region src/preview/preview/estimateClaimableAt.ts
3
+ /**
4
+ * Estimates when a newly requested delayed withdrawal becomes claimable:
5
+ * `now + withdrawalLength` of the cached withdrawable asset whose phantom
6
+ * token matches `phantomToken`. Same formula as
7
+ * `getWithdrawalRequestResult().claimableAt`.
8
+ *
9
+ * Returns `undefined` when the withdrawal compressor is missing, its assets
10
+ * cache is not loaded, or no asset matches the phantom token.
11
+ */
12
+ function estimateClaimableAt(sdk, phantomToken) {
13
+ const compressor = sdk.withdrawalCompressor;
14
+ if (!compressor?.state) return;
15
+ const asset = compressor.getWithdrawableAssets().find((a) => isAddressEqual(a.withdrawalPhantomToken, phantomToken));
16
+ if (!asset) return;
17
+ return Math.floor(Date.now() / 1e3) + Number(asset.withdrawalLength);
18
+ }
19
+ //#endregion
20
+ export { estimateClaimableAt };
@@ -4,9 +4,10 @@ import { classifyCloseOrRepay, isCloseOrRepay } from "./detectCloseOrRepay.js";
4
4
  import { detectDelayedClaim, resolveDelayedClaimIntent } from "./detectDelayedClaim.js";
5
5
  import { detectDelayedOperation } from "./detectDelayedOperation.js";
6
6
  import { UnsupportedOperationError } from "./errors.js";
7
+ import { estimateClaimableAt } from "./estimateClaimableAt.js";
7
8
  import { makeReplayState, replayInnerOperations } from "./replayInnerOperations.js";
8
9
  import { replayMulticall } from "./replayMulticall.js";
9
10
  import { previewAdjustStrategyPosition } from "./previewAdjustStrategyPosition.js";
10
11
  import { previewExitOrRepayStrategyPosition } from "./previewExitOrRepayStrategyPosition.js";
11
12
  import { previewOperation } from "./previewOperation.js";
12
- export { CreditAccountState, UnsupportedOperationError, buildDelayedStrategyPositionOperationPreview, classifyCloseOrRepay, detectDelayedClaim, detectDelayedOperation, isCloseOrRepay, makeReplayState, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
13
+ export { CreditAccountState, UnsupportedOperationError, buildDelayedStrategyPositionOperationPreview, classifyCloseOrRepay, detectDelayedClaim, detectDelayedOperation, estimateClaimableAt, isCloseOrRepay, makeReplayState, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
@@ -16,6 +16,7 @@ import { unwrapNativeCollateral } from "./unwrapNativeCollateral.js";
16
16
  function previewAdjustStrategyPosition(input, operation, options) {
17
17
  const { sdk, value = 0n } = input;
18
18
  const market = sdk.marketRegister.findByCreditManager(operation.creditManager);
19
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
19
20
  const oracle = market.priceOracle;
20
21
  const { before, after, error: replayError } = replayMulticall(sdk, operation, options);
21
22
  const account = after.account;
@@ -39,6 +40,8 @@ function previewAdjustStrategyPosition(input, operation, options) {
39
40
  operation: "AdjustCreditAccount",
40
41
  ...asEstimated(sdk.positions.projection(snap, { availableLiquidityChange: before.totalDebt - account.totalDebt })),
41
42
  creditAccount: operation.creditAccount,
43
+ name: suite.accountStrategyName(operation.creditAccount),
44
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
42
45
  collateralAdded: collateralAdded.map((a) => oracle.toTokenAmount(a.token, a.balance)),
43
46
  collateralWithdrawn: after.collateralWithdrawn.toAssets().map((a) => oracle.toTokenAmount(a.token, a.balance)),
44
47
  totalDebtChange: market.toUnderlyingAmount(account.totalDebt - before.totalDebt),
@@ -24,6 +24,7 @@ function previewCloseCreditAccount(input, operation, permanent, replay) {
24
24
  const { sdk } = input;
25
25
  const market = sdk.marketRegister.findByCreditManager(operation.creditManager);
26
26
  const { after, error } = replay;
27
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
27
28
  let receivedToken = market.underlying;
28
29
  for (const m of operation.multicall) if (m.operation === "WithdrawCollateral" && m.amount === 115792089237316195423570985008687907853269984665640564039457584007913129639935n) {
29
30
  receivedToken = m.token;
@@ -32,8 +33,10 @@ function previewCloseCreditAccount(input, operation, permanent, replay) {
32
33
  return {
33
34
  operation: "CloseCreditAccount",
34
35
  permanent,
35
- ...creditOperationMarket(sdk.marketRegister.findCreditManager(operation.creditManager)),
36
+ ...creditOperationMarket(suite),
36
37
  creditAccount: operation.creditAccount,
38
+ name: suite.accountStrategyName(operation.creditAccount),
39
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
37
40
  receivedAmount: market.priceOracle.toTokenAmount(receivedToken, after.collateralWithdrawn.getOrZero(receivedToken)),
38
41
  error
39
42
  };
@@ -49,11 +52,14 @@ function previewRepayCreditAccount(input, operation, permanent, replay) {
49
52
  const { before, after, error: replayError } = replay;
50
53
  const { assets: collateralAdded, error: unwrapError } = unwrapNativeCollateral(after.collateralAdded.toAssets(), value, sdk.addressProvider.getAddress(AP_WETH_TOKEN, 0));
51
54
  const error = replayError ?? unwrapError;
55
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
52
56
  return {
53
57
  operation: "RepayCreditAccount",
54
58
  permanent,
55
- ...creditOperationMarket(sdk.marketRegister.findCreditManager(operation.creditManager)),
59
+ ...creditOperationMarket(suite),
56
60
  creditAccount: operation.creditAccount,
61
+ name: suite.accountStrategyName(operation.creditAccount),
62
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
57
63
  collateralAdded: collateralAdded.map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
58
64
  debtRepaid: market.toUnderlyingAmount(before.totalDebt - after.account.totalDebt),
59
65
  collateralWithdrawn: after.collateralWithdrawn.toAssets().map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
@@ -8,6 +8,7 @@ import { isCloseOrRepay } from "./detectCloseOrRepay.js";
8
8
  import { resolveDelayedClaimIntent } from "./detectDelayedClaim.js";
9
9
  import { detectDelayedOperation } from "./detectDelayedOperation.js";
10
10
  import { UnsupportedOperationError } from "./errors.js";
11
+ import { estimateClaimableAt } from "./estimateClaimableAt.js";
11
12
  import { replayMulticall } from "./replayMulticall.js";
12
13
  import { previewAdjustStrategyPosition } from "./previewAdjustStrategyPosition.js";
13
14
  import { previewExitOrRepayStrategyPosition } from "./previewExitOrRepayStrategyPosition.js";
@@ -65,11 +66,15 @@ async function previewMulticallOperation(input, operation, options) {
65
66
  const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
66
67
  const meta = sdk.tokensMeta.get(market.underlying);
67
68
  const receivedToken = meta && sdk.tokensMeta.isRWAUnderlying(meta) ? meta.asset : market.underlying;
69
+ const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
68
70
  return {
69
71
  operation: "DelayedCreditAccountOperation",
70
72
  creditAccount: operation.creditAccount,
71
- ...creditOperationMarket(sdk.marketRegister.findCreditManager(operation.creditManager)),
73
+ ...creditOperationMarket(suite),
74
+ name: suite.accountStrategyName(operation.creditAccount),
75
+ targetCollateral: suite.accountTargetCollateral(operation.creditAccount),
72
76
  intent: delayed.intent,
77
+ estClaimableAt: estimateClaimableAt(sdk, delayed.request.phantomToken),
73
78
  instantPreview,
74
79
  delayedPreview: buildDelayedStrategyPositionOperationPreview(after.account, before, delayed, convert, receivedToken, sdk)
75
80
  };
@@ -15,6 +15,7 @@ async function previewPoolPositionOperation(input, operation, options) {
15
15
  operation: operation.operation,
16
16
  pool: operation.pool,
17
17
  name: sdk.tokensMeta.mustGetToken(operation.pool).name,
18
+ underlyingToken: market.underlyingToken,
18
19
  shareRate: market.pool.pool.dieselRate,
19
20
  tokenIn: market.priceOracle.toTokenAmount(tokenIn, sim.amountIn),
20
21
  tokenOut: market.priceOracle.toTokenAmount(tokenOut, sim.amountOut)
@@ -20,6 +20,15 @@ declare const liquidatableAccountFilterSchema: z.ZodObject<{
20
20
  declare const liquidatableAccountSchema: z.ZodObject<{
21
21
  creditManager: z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>;
22
22
  name: z.ZodString;
23
+ underlyingToken: z.ZodObject<{
24
+ chainId: z.ZodNumber;
25
+ address: z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>;
26
+ symbol: z.ZodString;
27
+ name: z.ZodString;
28
+ decimals: z.ZodNumber;
29
+ assetType: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"Stable">, z.ZodLiteral<"ETH">, z.ZodLiteral<"BTC">]>>;
30
+ wrappedAddress: z.ZodNullable<z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>>;
31
+ }, z.core.$strip>;
23
32
  curator: z.ZodObject<{
24
33
  address: z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>;
25
34
  name: z.ZodOptional<z.ZodEnum<{
@@ -212,6 +221,15 @@ declare const liquidationPositionSchema: z.ZodObject<{
212
221
  declare const liquidationDetailsSchema: z.ZodObject<{
213
222
  creditManager: z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>;
214
223
  name: z.ZodString;
224
+ underlyingToken: z.ZodObject<{
225
+ chainId: z.ZodNumber;
226
+ address: z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>;
227
+ symbol: z.ZodString;
228
+ name: z.ZodString;
229
+ decimals: z.ZodNumber;
230
+ assetType: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"Stable">, z.ZodLiteral<"ETH">, z.ZodLiteral<"BTC">]>>;
231
+ wrappedAddress: z.ZodNullable<z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>>;
232
+ }, z.core.$strip>;
215
233
  curator: z.ZodObject<{
216
234
  address: z.ZodCodec<z.ZodString, z.ZodCustom<`0x${string}`, `0x${string}`>>;
217
235
  name: z.ZodOptional<z.ZodEnum<{
@@ -1,4 +1,4 @@
1
- import { Bps, ChainId, Leverage, TokenAmount } from "./primitives.js";
1
+ import { Bps, ChainId, Leverage, Timestamp, Token, TokenAmount, UnderlyingToken } from "./primitives.js";
2
2
  import { Curator } from "./curators.js";
3
3
  import { DelayedIntent } from "./delayed-intents.js";
4
4
  import { BorrowRateBreakdown } from "./positions.js";
@@ -112,6 +112,13 @@ interface PoolPositionOperationPreview {
112
112
  * Human-readable pool name
113
113
  */
114
114
  name: string;
115
+ /**
116
+ * Pool underlying token.
117
+ *
118
+ * For RWA markets this is the unwrapped asset, e.g. USDC rather than
119
+ * dcUSDC (the pool's on-chain underlying). Same as {@link PoolPosition.underlyingToken}.
120
+ */
121
+ underlyingToken: UnderlyingToken;
115
122
  /**
116
123
  * Token that goes from user to pool
117
124
  * In case of deposit, underlying for direct deposit, zapper input for zapper-routed deposit
@@ -157,9 +164,18 @@ interface CreditOperationMarket {
157
164
  */
158
165
  creditManager: Address;
159
166
  /**
160
- * Human-readable credit manager name.
167
+ * Human-readable strategy name, e.g. `"wstETH / WETH"`. Same as
168
+ * {@link StrategyPosition.name}
161
169
  */
162
170
  name: string;
171
+ /**
172
+ * Pool underlying token.
173
+ *
174
+ * For RWA markets this is the unwrapped asset, e.g. USDC rather than
175
+ * dcUSDC (the pool's on-chain underlying). Same as
176
+ * {@link StrategyPosition.underlyingToken}.
177
+ */
178
+ underlyingToken: UnderlyingToken;
163
179
  /**
164
180
  * Curator of the market {@link creditManager} belongs to, in the same shape
165
181
  * {@link StrategyOpportunity} reports it: the market configurator's address,
@@ -403,6 +419,11 @@ interface AdjustStrategyPositionPreview extends EstimatedProjection, AccountStat
403
419
  * Credit account that is being adjusted
404
420
  */
405
421
  creditAccount: Address;
422
+ /**
423
+ * Collateral token this position is a strategy in. Same as
424
+ * {@link StrategyPosition.targetCollateral}
425
+ */
426
+ targetCollateral: Token | null;
406
427
  /**
407
428
  * Tokens that were added as collateral during account opening.
408
429
  *
@@ -448,6 +469,11 @@ interface ExitStrategyPositionPreview extends CreditOperationMarket {
448
469
  * Credit account that is being closed
449
470
  */
450
471
  creditAccount: Address;
472
+ /**
473
+ * Collateral token this position is a strategy in. Same as
474
+ * {@link StrategyPosition.targetCollateral}
475
+ */
476
+ targetCollateral: Token | null;
451
477
  /**
452
478
  * Token withdrawn to the user and its minimal guaranteed amount, from the
453
479
  * multicall replay (all collateral is swapped into the received token
@@ -488,6 +514,11 @@ interface RepayStrategyPositionPreview extends CreditOperationMarket {
488
514
  * Credit account that is being repaid
489
515
  */
490
516
  creditAccount: Address;
517
+ /**
518
+ * Collateral token this position is a strategy in. Same as
519
+ * {@link StrategyPosition.targetCollateral}
520
+ */
521
+ targetCollateral: Token | null;
491
522
  /**
492
523
  * Tokens added from the wallet to cover the debt (`addCollateral` calls).
493
524
  *
@@ -539,11 +570,22 @@ interface DelayedStrategyPositionOperationPreview extends CreditOperationMarket
539
570
  * Credit account the operation is performed on
540
571
  */
541
572
  creditAccount: Address;
573
+ /**
574
+ * Collateral token this position is a strategy in. Same as
575
+ * {@link StrategyPosition.targetCollateral}
576
+ */
577
+ targetCollateral: Token | null;
542
578
  /**
543
579
  * Decoded from the withdrawal request's extraData; undefined when the
544
580
  * request carries no intent (e.g. Mellow)
545
581
  */
546
582
  intent?: DelayedIntent;
583
+ /**
584
+ * Estimated unix timestamp (seconds) when the delayed outputs become
585
+ * claimable: `now + withdrawalLength` of phantom token.
586
+ * Undefined when the compressor has no information about the asset.
587
+ */
588
+ estClaimableAt?: Timestamp;
547
589
  /**
548
590
  * What this transaction does right now: the delayed withdrawal is
549
591
  * represented by the phantom token among the account's assets
@@ -1,4 +1,4 @@
1
- import { Timestamp } from "../../../model/primitives.js";
1
+ import { Timestamp, Token, UnderlyingToken } from "../../../model/primitives.js";
2
2
  import { StrategyOpportunity, StrategyOpportunityDetail } from "../../../model/opportunities.js";
3
3
  import "../../../model/index.js";
4
4
  import { CreditAccountData, CreditSuiteState } from "../../base/types.js";
@@ -71,6 +71,14 @@ declare class CreditSuite extends SDKConstruct {
71
71
  * Token borrowed from the pool and used as the account debt asset.
72
72
  */
73
73
  get underlying(): Address;
74
+ /**
75
+ * Pool underlying token as the shared read model describes it.
76
+ *
77
+ * For RWA markets this is the unwrapped asset, e.g. USDC rather than
78
+ * dcUSDC (the pool's on-chain underlying). Same as
79
+ * {@link MarketSuite.underlyingToken}.
80
+ */
81
+ get underlyingToken(): UnderlyingToken;
74
82
  /**
75
83
  * Parent market that contains this credit manager
76
84
  */
@@ -164,6 +172,24 @@ declare class CreditSuite extends SDKConstruct {
164
172
  * or `undefined` when {@link strategyTargetCollateral} cannot be resolved.
165
173
  */
166
174
  get strategyName(): string | undefined;
175
+ /**
176
+ * Collateral token an existing credit account in this suite is a strategy
177
+ * in. Same as {@link StrategyPosition.targetCollateral}.
178
+ *
179
+ * Resolution, in order:
180
+ * 1. a hardcoded per-account override, when present;
181
+ * 2. {@link strategyTargetCollateral};
182
+ * 3. `null` when neither can be resolved.
183
+ */
184
+ accountTargetCollateral(creditAccount: Address): Token | null;
185
+ /**
186
+ * Display name of an existing credit account in this suite, e.g.
187
+ * `"wstETH / WETH"`. Same as {@link StrategyPosition.name}.
188
+ *
189
+ * {@link accountTargetCollateral} over the underlying, or the underlying
190
+ * symbol when no target can be resolved.
191
+ */
192
+ accountStrategyName(creditAccount: Address): string;
167
193
  /**
168
194
  * Describes this suite's leveraged strategy as the shared read model does,
169
195
  * or `undefined` when {@link strategyTargetCollateral} cannot be resolved or
@@ -16,7 +16,7 @@ declare function totalLiquidationDiscount(suite: CreditSuite): Bps;
16
16
  /**
17
17
  * The market half of every credit operation result, read off the suite that
18
18
  * serves it: a preview, a projection, the open-strategy walk and a
19
- * liquidatable-account row all spread it, so the four fields are filled in one
19
+ * liquidatable-account row all spread it, so the five fields are filled in one
20
20
  * place and cannot drift apart between the halves of the SDK.
21
21
  *
22
22
  * The curator comes from the same getter {@link CreditSuite.strategyOpportunity}
@@ -32,6 +32,7 @@ import { buildDelayedStrategyPositionOperationPreview } from "./preview/buildDel
32
32
  import { classifyCloseOrRepay, isCloseOrRepay } from "./preview/detectCloseOrRepay.js";
33
33
  import { DetectedDelayedClaim, detectDelayedClaim, resolveDelayedClaimIntent } from "./preview/detectDelayedClaim.js";
34
34
  import { UnsupportedOperationError } from "./preview/errors.js";
35
+ import { estimateClaimableAt } from "./preview/estimateClaimableAt.js";
35
36
  import { previewAdjustStrategyPosition } from "./preview/previewAdjustStrategyPosition.js";
36
37
  import { CloseOrRepayOperation, previewExitOrRepayStrategyPosition } from "./preview/previewExitOrRepayStrategyPosition.js";
37
38
  import { previewOperation } from "./preview/previewOperation.js";
@@ -41,4 +42,4 @@ import "./preview/index.js";
41
42
  import { CheckOperationOptions, WeighedFactors, checkOperation, collateralIssue, marketIssues, quotaCountIssue } from "./validate/checkOperation.js";
42
43
  import { checkSimulation } from "./validate/checkSimulation.js";
43
44
  import "./validate/index.js";
44
- export { AdapterOperation, AdapterOperationBase, AddCollateralOp, AllowanceDetail, AllowancePrerequisite, AllowanceResult, BalanceDetail, BalancePrerequisite, BalanceResult, BorrowLimitBinding, CheckOperationOptions, ClassifyInnerOperationsProps, CloseCreditAccountOperation, CloseOrRepayOperation, CompareBalancesOp, CreditAccountOperation, CreditAccountState, CreditAccountStateProps, DecreaseDebtOp, DetectedDelayedClaim, DetectedDelayedOperation, DirectTokenTransferOperation, ExtractTransfersResult, FacadeCallType, FacadeOperationMetadata, FacadeParsedCall, IncreaseDebtOp, InnerFacadeOperation, InnerOperation, IntentPreviewError, LiquidateCreditAccountOperation, MulticallOperation, OpenCreditAccountOperation, Operation, OperationMetadata, OuterFacadeOperation, PartialLiquidationOperation, PoolDepositOperation, PoolMintOperation, PoolOperation, PoolRedeemOperation, PoolWithdrawOperation, Prerequisite, PrerequisiteContext, PrerequisiteError, PrerequisiteKind, PrerequisiteOutcome, PrerequisiteResult, PreviewErrorDetails, PreviewErrorReason, PreviewIssue, PreviewOperationInput, PreviewOperationOptions, PreviewRefusal, RWAMulticallOperation, RWAOpenCreditAccountOperation, RWAOpenRequirementsDetail, RWAOpenRequirementsPrerequisite, RWAOpenRequirementsResult, RWAOperation, RWAOperationMetadata, ReplayMulticallResult, ReplayState, ReplayableOperation, StoreExpectedBalancesOp, TokenTransfer, TraceAdapterExt, TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, UnsupportedOperationError, UnsupportedPoolFunctionError, UnsupportedTargetError, UnsupportedZapperFunctionError, UpdateQuotaOp, WeighedFactors, WithdrawCollateralAlignmentError, WithdrawCollateralEventInfo, WithdrawCollateralOp, buildDelayedStrategyPositionOperationPreview, checkOperation, checkPrerequisites, checkSimulation, classifyCloseOrRepay, classifyInnerOperations, collateralIssue, detectDelayedClaim, detectDelayedOperation, extractAdapterCallTraces, extractTransfers, findFacadeCalls, isCloseOrRepay, isPoolOperation, isRWAOperation, makeReplayState, marketIssues, parseFacadeOperationCalldata, parseOperationCalldata, parsePoolOperationCalldata, parseRWAFactoryOperationCalldata, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, quotaCountIssue, raise, refuse, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
45
+ export { AdapterOperation, AdapterOperationBase, AddCollateralOp, AllowanceDetail, AllowancePrerequisite, AllowanceResult, BalanceDetail, BalancePrerequisite, BalanceResult, BorrowLimitBinding, CheckOperationOptions, ClassifyInnerOperationsProps, CloseCreditAccountOperation, CloseOrRepayOperation, CompareBalancesOp, CreditAccountOperation, CreditAccountState, CreditAccountStateProps, DecreaseDebtOp, DetectedDelayedClaim, DetectedDelayedOperation, DirectTokenTransferOperation, ExtractTransfersResult, FacadeCallType, FacadeOperationMetadata, FacadeParsedCall, IncreaseDebtOp, InnerFacadeOperation, InnerOperation, IntentPreviewError, LiquidateCreditAccountOperation, MulticallOperation, OpenCreditAccountOperation, Operation, OperationMetadata, OuterFacadeOperation, PartialLiquidationOperation, PoolDepositOperation, PoolMintOperation, PoolOperation, PoolRedeemOperation, PoolWithdrawOperation, Prerequisite, PrerequisiteContext, PrerequisiteError, PrerequisiteKind, PrerequisiteOutcome, PrerequisiteResult, PreviewErrorDetails, PreviewErrorReason, PreviewIssue, PreviewOperationInput, PreviewOperationOptions, PreviewRefusal, RWAMulticallOperation, RWAOpenCreditAccountOperation, RWAOpenRequirementsDetail, RWAOpenRequirementsPrerequisite, RWAOpenRequirementsResult, RWAOperation, RWAOperationMetadata, ReplayMulticallResult, ReplayState, ReplayableOperation, StoreExpectedBalancesOp, TokenTransfer, TraceAdapterExt, TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, UnsupportedOperationError, UnsupportedPoolFunctionError, UnsupportedTargetError, UnsupportedZapperFunctionError, UpdateQuotaOp, WeighedFactors, WithdrawCollateralAlignmentError, WithdrawCollateralEventInfo, WithdrawCollateralOp, buildDelayedStrategyPositionOperationPreview, checkOperation, checkPrerequisites, checkSimulation, classifyCloseOrRepay, classifyInnerOperations, collateralIssue, detectDelayedClaim, detectDelayedOperation, estimateClaimableAt, extractAdapterCallTraces, extractTransfers, findFacadeCalls, isCloseOrRepay, isPoolOperation, isRWAOperation, makeReplayState, marketIssues, parseFacadeOperationCalldata, parseOperationCalldata, parsePoolOperationCalldata, parseRWAFactoryOperationCalldata, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, quotaCountIssue, raise, refuse, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
@@ -0,0 +1,19 @@
1
+ import { Timestamp } from "../../model/primitives.js";
2
+ import "../../model/index.js";
3
+ import { PluginsMap } from "../../onchain/plugins/types.js";
4
+ import { OnchainSDK } from "../../onchain/OnchainSDK.js";
5
+ import "../../onchain/index.js";
6
+ import { Address } from "viem";
7
+ //#region src/preview/preview/estimateClaimableAt.d.ts
8
+ /**
9
+ * Estimates when a newly requested delayed withdrawal becomes claimable:
10
+ * `now + withdrawalLength` of the cached withdrawable asset whose phantom
11
+ * token matches `phantomToken`. Same formula as
12
+ * `getWithdrawalRequestResult().claimableAt`.
13
+ *
14
+ * Returns `undefined` when the withdrawal compressor is missing, its assets
15
+ * cache is not loaded, or no asset matches the phantom token.
16
+ */
17
+ declare function estimateClaimableAt<P extends PluginsMap>(sdk: OnchainSDK<P>, phantomToken: Address): Timestamp | undefined;
18
+ //#endregion
19
+ export { estimateClaimableAt };
@@ -4,9 +4,10 @@ import { buildDelayedStrategyPositionOperationPreview } from "./buildDelayedStra
4
4
  import { classifyCloseOrRepay, isCloseOrRepay } from "./detectCloseOrRepay.js";
5
5
  import { DetectedDelayedClaim, detectDelayedClaim, resolveDelayedClaimIntent } from "./detectDelayedClaim.js";
6
6
  import { UnsupportedOperationError } from "./errors.js";
7
+ import { estimateClaimableAt } from "./estimateClaimableAt.js";
7
8
  import { previewAdjustStrategyPosition } from "./previewAdjustStrategyPosition.js";
8
9
  import { CloseOrRepayOperation, previewExitOrRepayStrategyPosition } from "./previewExitOrRepayStrategyPosition.js";
9
10
  import { previewOperation } from "./previewOperation.js";
10
11
  import { ReplayState, makeReplayState, replayInnerOperations } from "./replayInnerOperations.js";
11
12
  import { ReplayMulticallResult, ReplayableOperation, replayMulticall } from "./replayMulticall.js";
12
- export { CloseOrRepayOperation, CreditAccountState, CreditAccountStateProps, DetectedDelayedClaim, DetectedDelayedOperation, ReplayMulticallResult, ReplayState, ReplayableOperation, UnsupportedOperationError, buildDelayedStrategyPositionOperationPreview, classifyCloseOrRepay, detectDelayedClaim, detectDelayedOperation, isCloseOrRepay, makeReplayState, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
13
+ export { CloseOrRepayOperation, CreditAccountState, CreditAccountStateProps, DetectedDelayedClaim, DetectedDelayedOperation, ReplayMulticallResult, ReplayState, ReplayableOperation, UnsupportedOperationError, buildDelayedStrategyPositionOperationPreview, classifyCloseOrRepay, detectDelayedClaim, detectDelayedOperation, estimateClaimableAt, isCloseOrRepay, makeReplayState, previewAdjustStrategyPosition, previewExitOrRepayStrategyPosition, previewOperation, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "16.0.0-next.36",
3
+ "version": "16.0.0-next.38",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {