@gearbox-protocol/sdk 16.0.0-next.45 → 16.0.0-next.46

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 (30) hide show
  1. package/dist/cjs/model/index.js +1 -0
  2. package/dist/cjs/model/withdrawals.schema.js +7 -2
  3. package/dist/cjs/onchain/accounts/intents/index.js +38 -13
  4. package/dist/cjs/onchain/accounts/intents/tail.js +112 -5
  5. package/dist/cjs/onchain/pools/PoolService.js +20 -4
  6. package/dist/cjs/onchain/positions/PositionsService.js +8 -2
  7. package/dist/cjs/sdk/prepare/PrepareApi.js +133 -82
  8. package/dist/esm/model/index.js +2 -2
  9. package/dist/esm/model/withdrawals.schema.js +7 -3
  10. package/dist/esm/onchain/accounts/intents/index.js +38 -13
  11. package/dist/esm/onchain/accounts/intents/tail.js +112 -5
  12. package/dist/esm/onchain/pools/PoolService.js +20 -4
  13. package/dist/esm/onchain/positions/PositionsService.js +8 -2
  14. package/dist/esm/sdk/prepare/PrepareApi.js +133 -82
  15. package/dist/types/model/index.d.ts +3 -3
  16. package/dist/types/model/withdrawals.d.ts +24 -5
  17. package/dist/types/model/withdrawals.schema.d.ts +21 -1
  18. package/dist/types/onchain/accounts/index.d.ts +2 -2
  19. package/dist/types/onchain/accounts/intents/index.d.ts +19 -11
  20. package/dist/types/onchain/accounts/intents/tail.d.ts +13 -3
  21. package/dist/types/onchain/accounts/intents/types.d.ts +74 -1
  22. package/dist/types/onchain/index.d.ts +3 -3
  23. package/dist/types/onchain/pools/PoolService.d.ts +10 -1
  24. package/dist/types/onchain/pools/index.d.ts +2 -2
  25. package/dist/types/onchain/pools/types.d.ts +40 -1
  26. package/dist/types/sdk/index.d.ts +3 -3
  27. package/dist/types/sdk/prepare/PrepareApi.d.ts +8 -7
  28. package/dist/types/sdk/prepare/index.d.ts +3 -3
  29. package/dist/types/sdk/prepare/types.d.ts +85 -28
  30. package/package.json +1 -1
@@ -45,21 +45,27 @@ var CreditAccountOperationsService = class extends SDKConstruct {
45
45
  }));
46
46
  }
47
47
  /**
48
- * Largest `WITHDRAW` amount (in underlying) the account can take out while
49
- * keeping leverage and staying inside the facade's debt band — the ceiling a
50
- * withdraw form should offer. Taking everything out is the same intent with
51
- * `MAX_UINT256` for an amount, and needs none of this arithmetic.
48
+ * Both ends of what a `WITHDRAW` can take out, in underlying: the largest
49
+ * partial withdrawal that keeps leverage and stays inside the facade's debt
50
+ * band, and the net value an exit hands over. They are reported together
51
+ * because a withdraw form needs both the range it may offer, and the one
52
+ * amount past it that is allowed — and because the distance between them is
53
+ * the account's own, not a constant a caller could assume.
52
54
  *
53
55
  * Takes no target health factor, unlike {@link maxWithdrawCollateral}: a
54
56
  * proportional withdrawal leaves the factor where it found it, and the
55
57
  * facade's `minDebt` is what bounds it.
56
58
  *
57
59
  * @param props - Account slice and the SDK holding its market
58
- * @returns Amount in underlying units; `0n` when nothing can leave
60
+ * @returns The two ceilings, see {@link WithdrawCeilings} for the gap between
61
+ * them
59
62
  */
60
63
  maxWithdraw(props) {
61
64
  const view = accountView(props.creditAccount, props.sdk);
62
- return maxProportionalWithdrawal(view, view.band);
65
+ return {
66
+ partial: maxProportionalWithdrawal(view, view.band),
67
+ exit: view.collateral > 0n ? view.collateral : 0n
68
+ };
63
69
  }
64
70
  /**
65
71
  * Debt a `REPAY` would have to cover to settle the account, in underlying
@@ -229,17 +235,36 @@ var CreditAccountOperationsService = class extends SDKConstruct {
229
235
  * whole tail: the tokens land on the account and only their quota has to
230
236
  * catch up.
231
237
  *
238
+ * A claim that brought only part of what the request queued — a legacy Mellow
239
+ * multivault, which pays out what it holds liquid and re-queues the rest — is
240
+ * served in proportion, and what it did not settle comes back as `remainder`:
241
+ * the withdrawal still in flight and the intent to finish it with.
242
+ *
232
243
  * @param props - The recorded intent, the account slice as it stands now, and
233
244
  * the matured claimable
234
- * @returns Shaped exactly like {@link startIntent}'s result, so both halves of
235
- * an operation are consumed the same way
245
+ * @returns Shaped exactly like {@link startIntent}'s result with the remainder
246
+ * beside it, so both halves of an operation are consumed the same way
236
247
  */
237
248
  async finishIntent(props) {
238
- return plain(await this.#preview(props, () => planTail({
239
- intent: props.intent,
240
- claimable: props.claimable,
241
- view: accountView(props.creditAccount, props.sdk)
242
- })));
249
+ let remainder;
250
+ const result = await this.#preview(props, () => {
251
+ const tail = planTail({
252
+ intent: props.intent,
253
+ claimable: props.claimable,
254
+ view: accountView(props.creditAccount, props.sdk)
255
+ });
256
+ remainder = tail.remainder;
257
+ return tail.steps;
258
+ });
259
+ if (!result.ok) return result;
260
+ const { operations, state, calls } = result;
261
+ return {
262
+ ok: true,
263
+ operations,
264
+ state,
265
+ calls,
266
+ remainder
267
+ };
243
268
  }
244
269
  /**
245
270
  * Previews opening a brand-new leveraged position.
@@ -1,4 +1,6 @@
1
1
  import { IntentPreviewError } from "../../validation/refusal.js";
2
+ import { toTokenAmount } from "../../validation/token.js";
3
+ import { toTargetDecimals } from "./utils/common.js";
2
4
  import { createOraclePaths } from "./utils/router-path.js";
3
5
  import { planFinishClaimOnly, planFinishCloseAccount, planFinishDecreaseLeverage, planFinishWithdraw } from "./plan.js";
4
6
  import { instantOutput } from "./operations.js";
@@ -12,6 +14,10 @@ import { accountView } from "./view.js";
12
14
  * Shared by the two callers that need it and must not disagree — the tail as
13
15
  * it is previewed days later against the account that really exists, and the
14
16
  * tail as it is projected the moment the request is made.
17
+ *
18
+ * A claim that brought only part of what was queued is served in proportion,
19
+ * see {@link partialTail}: the intent's payout and its repayment are cut to the
20
+ * share that arrived, and the rest of both is handed to the next claim.
15
21
  */
16
22
  function planTail(args) {
17
23
  const { intent, claimable, view } = args;
@@ -20,17 +26,118 @@ function planTail(args) {
20
26
  if (!output) throw new IntentPreviewError("insufficientSourceBalance", void 0, "finishIntent: the claim credits nothing to spend");
21
27
  return output;
22
28
  };
29
+ const queued = claimable.outputs.find((o) => o.isDelayed && o.amount > 0n);
30
+ if (queued) return partialTail({
31
+ intent,
32
+ claimable,
33
+ queued,
34
+ view
35
+ });
23
36
  switch (intent.type) {
24
- case "WITHDRAW_COLLATERAL": return planFinishWithdraw(intent, claimable, claimed(), view);
25
- case "DECREASE_LEVERAGE": return planFinishDecreaseLeverage(claimable, claimed(), view);
26
- case "CLOSE_ACCOUNT": return planFinishCloseAccount(intent, claimable, claimed(), view);
37
+ case "WITHDRAW_COLLATERAL": return whole(planFinishWithdraw(intent, claimable, claimed(), view));
38
+ case "DECREASE_LEVERAGE": return whole(planFinishDecreaseLeverage(claimable, claimed(), view));
39
+ case "CLOSE_ACCOUNT": return whole(planFinishCloseAccount(intent, claimable, claimed(), view));
27
40
  case "ADD_COLLATERAL":
28
41
  case "INCREASE_LEVERAGE":
29
42
  case "DEPOSIT":
30
- case "DEPOSIT_AND_INCREASE_LEVERAGE": return planFinishClaimOnly(claimable);
43
+ case "DEPOSIT_AND_INCREASE_LEVERAGE": return whole(planFinishClaimOnly(claimable));
31
44
  default: throw new Error(`${intent.type} - not implemented`);
32
45
  }
33
46
  }
47
+ const whole = (steps) => ({
48
+ steps,
49
+ remainder: void 0
50
+ });
51
+ /**
52
+ * The tail of a claim that settled only part of the withdrawal it matured.
53
+ *
54
+ * Only a legacy Mellow multivault answers one this way — it pays out what its
55
+ * subvaults hold liquid and queues the rest — and the engine cannot finish an
56
+ * intent it has been given a fraction of the funds for. So the fraction is what
57
+ * it serves: the payout and the repayment are cut in the proportion that
58
+ * arrived, which keeps the withdrawal at the fixed leverage it was asked for
59
+ * instead of paying the wallet out first and deleveraging a claim later, and
60
+ * the untouched half of each is carried to the next claim by the remainder.
61
+ *
62
+ * Two intents cannot be served in part at all. An exit sells the account whole,
63
+ * and it cannot while a withdrawal is in flight — the phantom is neither
64
+ * sellable nor transferable — so a partial claim only repays what it brought
65
+ * and the account is emptied by the claim that brings the last of it. A claim
66
+ * that credited nothing at all leaves nothing to spend, so it is taken alone:
67
+ * it is still worth sending, since it is what moves the queue.
68
+ */
69
+ function partialTail(args) {
70
+ const { intent, claimable, queued, view } = args;
71
+ const inFlight = toTokenAmount(view.sdk, queued.token, queued.amount);
72
+ const claimed = instantOutput(claimable.outputs);
73
+ if (!claimed) return {
74
+ steps: planFinishClaimOnly(claimable),
75
+ remainder: {
76
+ inFlight,
77
+ intent
78
+ }
79
+ };
80
+ switch (intent.type) {
81
+ case "WITHDRAW_COLLATERAL": {
82
+ const served = arrivedShare(claimed, queued, view.sdk);
83
+ const withdrawAmount = part(intent.withdrawAmount, served);
84
+ const debtRepaid = part(intent.debtRepaid, served);
85
+ return {
86
+ steps: planFinishWithdraw({
87
+ ...intent,
88
+ withdrawAmount,
89
+ debtRepaid
90
+ }, claimable, claimed, view),
91
+ remainder: {
92
+ inFlight,
93
+ intent: {
94
+ ...intent,
95
+ withdrawAmount: intent.withdrawAmount - withdrawAmount,
96
+ debtRepaid: intent.debtRepaid - debtRepaid
97
+ }
98
+ }
99
+ };
100
+ }
101
+ case "DECREASE_LEVERAGE":
102
+ case "CLOSE_ACCOUNT": return {
103
+ steps: planFinishDecreaseLeverage(claimable, claimed, view),
104
+ remainder: {
105
+ inFlight,
106
+ intent
107
+ }
108
+ };
109
+ case "ADD_COLLATERAL":
110
+ case "INCREASE_LEVERAGE":
111
+ case "DEPOSIT":
112
+ case "DEPOSIT_AND_INCREASE_LEVERAGE": return {
113
+ steps: planFinishClaimOnly(claimable),
114
+ remainder: {
115
+ inFlight,
116
+ intent
117
+ }
118
+ };
119
+ default: throw new Error(`${intent.type} - not implemented`);
120
+ }
121
+ }
122
+ /**
123
+ * How much of the redemption this claim was: what it credited, over that plus
124
+ * what it left queued.
125
+ *
126
+ * The phantom stands for its payout one for one — the same reading the request
127
+ * side takes when it names the claim it expects — so only the decimals of the
128
+ * two have to be reconciled before they can be added up.
129
+ */
130
+ function arrivedShare(claimed, queued, sdk) {
131
+ const rest = toTargetDecimals(queued.amount, queued.token, claimed.token, sdk);
132
+ return {
133
+ got: claimed.amount,
134
+ of: claimed.amount + rest
135
+ };
136
+ }
137
+ /** A share of an amount, rounded down: a tail never promises more than it has. */
138
+ function part(amount, share) {
139
+ return share.of > 0n ? amount * share.got / share.of : 0n;
140
+ }
34
141
  /**
35
142
  * Where a delayed intent ends up, worked out at the moment it is started.
36
143
  *
@@ -55,7 +162,7 @@ async function projectTail(args) {
55
162
  const queued = request.outputs.find((o) => o.isDelayed);
56
163
  if (!queued || !claim) throw new IntentPreviewError("noRecordedIntent", void 0, "projectTail: the request queued nothing to claim");
57
164
  const next = sliceAfter(creditAccount, delayed.afterRequest);
58
- const steps = planTail({
165
+ const { steps } = planTail({
59
166
  intent: delayed.record,
60
167
  claimable: projectedClaimable(request, queued.token, queued.amount, claim),
61
168
  view: accountView(next, sdk)
@@ -29,6 +29,25 @@ function payoutCeiling(market) {
29
29
  return market.priceOracle.toAmount(pool.underlying, pool.pool.availableLiquidity * LIQUIDITY_SAFETY_NUM / LIQUIDITY_SAFETY_DENOM);
30
30
  }
31
31
  var PoolService = class extends SDKConstruct {
32
+ /**
33
+ * {@inheritDoc IPoolsService.getShareBalance}
34
+ */
35
+ async getShareBalance(props) {
36
+ return this.client.readContract({
37
+ address: this.sdk.marketRegister.findByPool(props.pool).pool.pool.address,
38
+ abi: ierc20Abi,
39
+ functionName: "balanceOf",
40
+ args: [props.wallet],
41
+ blockNumber: props.blockNumber
42
+ });
43
+ }
44
+ /**
45
+ * {@inheritDoc IPoolsService.sharesToUnderlying}
46
+ */
47
+ sharesToUnderlying(pool, shares) {
48
+ const market = this.sdk.marketRegister.findByPool(pool);
49
+ return market.toUnderlyingAmount(shares * market.pool.pool.dieselRate / RAY);
50
+ }
32
51
  /**
33
52
  * {@inheritDoc IPoolsService.getDepositTokensIn}
34
53
  */
@@ -414,10 +433,7 @@ var PoolService = class extends SDKConstruct {
414
433
  chainId: this.chainId,
415
434
  pool: pool.address,
416
435
  underlyingToken: market.underlyingToken,
417
- netValue: {
418
- token: this.sdk.tokensMeta.mustGetToken(market.unwrappedUnderlying),
419
- ...market.priceOracle.toAmount(market.underlying, shares * pool.dieselRate / RAY)
420
- },
436
+ netValue: this.sharesToUnderlying(pool.address, shares),
421
437
  apy: { organicApy: rayToBps(pool.supplyRate) }
422
438
  };
423
439
  }
@@ -372,7 +372,10 @@ var PositionsService = class extends SDKConstruct {
372
372
  return {
373
373
  sourceToken: this.sdk.tokensMeta.mustGetToken(w.token),
374
374
  withdrawalPhantomToken: priceOracle.toTokenAmount(w.withdrawalPhantomToken, w.withdrawalTokenSpent),
375
- outputs: w.outputs.map((o) => priceOracle.toTokenAmount(o.token, o.amount)),
375
+ outputs: w.outputs.map((o) => ({
376
+ ...priceOracle.toTokenAmount(o.token, o.amount),
377
+ isDelayed: o.isDelayed
378
+ })),
376
379
  claimCall: this.#claimTx(w.claimCalls, w.token),
377
380
  redeemer: w.redeemer,
378
381
  intent: w.intent
@@ -382,7 +385,10 @@ var PositionsService = class extends SDKConstruct {
382
385
  return {
383
386
  sourceToken: this.sdk.tokensMeta.mustGetToken(w.token),
384
387
  withdrawalPhantomToken: this.sdk.tokensMeta.mustGetToken(w.withdrawalPhantomToken),
385
- expectedOutputs: w.expectedOutputs.map((o) => priceOracle.toTokenAmount(o.token, o.amount)),
388
+ expectedOutputs: w.expectedOutputs.map((o) => ({
389
+ ...priceOracle.toTokenAmount(o.token, o.amount),
390
+ isDelayed: o.isDelayed
391
+ })),
386
392
  claimableAt: Number(w.claimableAt),
387
393
  redeemer: w.redeemer,
388
394
  intent: w.intent
@@ -58,7 +58,7 @@ var PrepareApi = class extends MultichainConstruct {
58
58
  }));
59
59
  const creditAccount = await slice(sdk, position.creditAccount);
60
60
  if (!creditAccount) return sdkErr(creditAccountNotFound(position.creditAccount));
61
- return planned(await service(sdk).finishIntent({
61
+ return finalized(await service(sdk).finishIntent({
62
62
  intent,
63
63
  claimable: toClaimableWithdrawal(params.claimable),
64
64
  creditAccount,
@@ -73,94 +73,106 @@ var PrepareApi = class extends MultichainConstruct {
73
73
  /**
74
74
  * {@inheritDoc IOpportunitiesPrepare.deposit}
75
75
  **/
76
- deposit(pool, params) {
77
- const chain = this.sdk.chain(pool.chainId);
78
- const { marketRegister, pools } = chain;
79
- const tokenIn = params.tokenIn ?? marketRegister.findByPool(pool.pool).pool.underlying;
80
- const tokenOut = lpRoute(params.tokenOut, () => pools.getDepositTokensOut(pool.pool, tokenIn));
81
- if (!tokenOut) return unroutable(chain, tokenIn, void 0);
82
- const state = pools.simulateDeposit({
83
- pool: pool.pool,
84
- amount: params.amount,
85
- tokenIn,
86
- tokenOut
87
- });
88
- const call = pools.addLiquidity({
89
- collateral: {
90
- token: state.tokenIn.token.address,
91
- balance: state.tokenIn.value
92
- },
93
- pool: pool.pool,
94
- wallet: params.wallet,
95
- meta: pools.getDepositMetadata(pool.pool, tokenIn, tokenOut)
96
- });
97
- if (!call) return unroutable(chain, tokenIn, tokenOut);
98
- return sdkOk({
99
- operations: [],
100
- state,
101
- calls: call.calls,
102
- ...stateBlock(chain)
103
- });
76
+ async deposit(pool, params) {
77
+ try {
78
+ const chain = await this.#chain(pool.chainId);
79
+ const { marketRegister, pools } = chain;
80
+ const tokenIn = params.tokenIn ?? marketRegister.findByPool(pool.pool).pool.underlying;
81
+ const tokenOut = lpRoute(params.tokenOut, () => pools.getDepositTokensOut(pool.pool, tokenIn));
82
+ if (!tokenOut) return unroutable(chain, tokenIn, void 0);
83
+ const state = pools.simulateDeposit({
84
+ pool: pool.pool,
85
+ amount: params.amount,
86
+ tokenIn,
87
+ tokenOut
88
+ });
89
+ const call = pools.addLiquidity({
90
+ collateral: {
91
+ token: state.tokenIn.token.address,
92
+ balance: state.tokenIn.value
93
+ },
94
+ pool: pool.pool,
95
+ wallet: params.wallet,
96
+ meta: pools.getDepositMetadata(pool.pool, tokenIn, tokenOut)
97
+ });
98
+ if (!call) return unroutable(chain, tokenIn, tokenOut);
99
+ return sdkOk({
100
+ operations: [],
101
+ state: await lpState(chain, pool.pool, params.wallet, state, { mints: state.tokenOut.value }),
102
+ calls: call.calls,
103
+ ...stateBlock(chain)
104
+ });
105
+ } catch (e) {
106
+ return sdkErr(unexpectedFailure(e));
107
+ }
104
108
  }
105
109
  /**
106
110
  * {@inheritDoc IOpportunitiesPrepare.withdraw}
107
111
  **/
108
- withdraw(pool, params) {
109
- const chain = this.sdk.chain(pool.chainId);
110
- const { pools } = chain;
111
- const tokenIn = params.tokenIn ?? pool.pool;
112
- const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
113
- if (!tokenOut) return unroutable(chain, tokenIn, void 0);
114
- const state = pools.simulateWithdraw({
115
- pool: pool.pool,
116
- amount: params.amount,
117
- tokenIn,
118
- tokenOut
119
- });
120
- const { calls } = pools.removeLiquidity({
121
- pool: pool.pool,
122
- amount: params.amount,
123
- wallet: params.wallet,
124
- permit: void 0,
125
- meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
126
- mode: "withdraw"
127
- });
128
- return sdkOk({
129
- operations: [],
130
- state,
131
- calls,
132
- ...stateBlock(chain)
133
- });
112
+ async withdraw(pool, params) {
113
+ try {
114
+ const chain = await this.#chain(pool.chainId);
115
+ const { pools } = chain;
116
+ const tokenIn = params.tokenIn ?? pool.pool;
117
+ const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
118
+ if (!tokenOut) return unroutable(chain, tokenIn, void 0);
119
+ const state = pools.simulateWithdraw({
120
+ pool: pool.pool,
121
+ amount: params.amount,
122
+ tokenIn,
123
+ tokenOut
124
+ });
125
+ const { calls } = pools.removeLiquidity({
126
+ pool: pool.pool,
127
+ amount: params.amount,
128
+ wallet: params.wallet,
129
+ permit: void 0,
130
+ meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
131
+ mode: "withdraw"
132
+ });
133
+ return sdkOk({
134
+ operations: [],
135
+ state: await lpState(chain, pool.pool, params.wallet, state, { burns: state.tokenIn.value }),
136
+ calls,
137
+ ...stateBlock(chain)
138
+ });
139
+ } catch (e) {
140
+ return sdkErr(unexpectedFailure(e));
141
+ }
134
142
  }
135
143
  /**
136
144
  * {@inheritDoc IOpportunitiesPrepare.redeem}
137
145
  **/
138
- redeem(pool, params) {
139
- const chain = this.sdk.chain(pool.chainId);
140
- const { pools } = chain;
141
- const tokenIn = params.tokenIn ?? pool.pool;
142
- const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
143
- if (!tokenOut) return unroutable(chain, tokenIn, void 0);
144
- const state = pools.simulateRedeem({
145
- pool: pool.pool,
146
- amount: params.amount,
147
- tokenIn,
148
- tokenOut
149
- });
150
- const { calls } = pools.removeLiquidity({
151
- pool: pool.pool,
152
- amount: params.amount,
153
- wallet: params.wallet,
154
- permit: void 0,
155
- meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
156
- mode: "redeem"
157
- });
158
- return sdkOk({
159
- operations: [],
160
- state,
161
- calls,
162
- ...stateBlock(chain)
163
- });
146
+ async redeem(pool, params) {
147
+ try {
148
+ const chain = await this.#chain(pool.chainId);
149
+ const { pools } = chain;
150
+ const tokenIn = params.tokenIn ?? pool.pool;
151
+ const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
152
+ if (!tokenOut) return unroutable(chain, tokenIn, void 0);
153
+ const state = pools.simulateRedeem({
154
+ pool: pool.pool,
155
+ amount: params.amount,
156
+ tokenIn,
157
+ tokenOut
158
+ });
159
+ const { calls } = pools.removeLiquidity({
160
+ pool: pool.pool,
161
+ amount: params.amount,
162
+ wallet: params.wallet,
163
+ permit: void 0,
164
+ meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
165
+ mode: "redeem"
166
+ });
167
+ return sdkOk({
168
+ operations: [],
169
+ state: await lpState(chain, pool.pool, params.wallet, state, { burns: state.tokenIn.value }),
170
+ calls,
171
+ ...stateBlock(chain)
172
+ });
173
+ } catch (e) {
174
+ return sdkErr(unexpectedFailure(e));
175
+ }
164
176
  }
165
177
  /**
166
178
  * {@inheritDoc IOpportunitiesPrepare.openNewStrategy}
@@ -412,7 +424,7 @@ function toClaimableWithdrawal(claimable) {
412
424
  outputs: claimable.outputs.map((o) => ({
413
425
  token: o.token.address,
414
426
  amount: o.value,
415
- isDelayed: false
427
+ isDelayed: o.isDelayed
416
428
  })),
417
429
  claimCalls: [{
418
430
  target: claimable.claimCall.to,
@@ -469,6 +481,23 @@ function planned(result, at) {
469
481
  }
470
482
  /**
471
483
  * {@inheritDoc planned}
484
+ *
485
+ * A tail carries one thing the other results do not: whether the claim it was
486
+ * built on finished the withdrawal, or left part of it queued for another one.
487
+ **/
488
+ function finalized(result, at) {
489
+ if (!result.ok) return refusal(result);
490
+ const { operations, state, calls, remainder } = result;
491
+ return sdkOk({
492
+ operations,
493
+ state,
494
+ calls,
495
+ remainder,
496
+ ...at
497
+ });
498
+ }
499
+ /**
500
+ * {@inheritDoc planned}
472
501
  **/
473
502
  function opened(result, at) {
474
503
  return result.ok ? sdkOk({
@@ -511,6 +540,28 @@ function routed(result, at) {
511
540
  });
512
541
  }
513
542
  /**
543
+ * The pool's own numbers as the namespace reports them: the trade the service
544
+ * priced, the market it belongs to, and where the wallet's position lands.
545
+ *
546
+ * The position is measured in shares and converted once, rather than added up
547
+ * in underlying, so the figure is exactly what a later
548
+ * `sdk.positions.list()` will report — the same balance through the same rate.
549
+ * A withdrawal larger than the position floors at nothing: the transaction
550
+ * would revert long before it got there, and a negative holding is not a thing
551
+ * a screen can show.
552
+ **/
553
+ async function lpState(sdk, pool, wallet, simulation, moved) {
554
+ const after = await sdk.pools.getShareBalance({
555
+ pool,
556
+ wallet
557
+ }) + (moved.mints ?? -moved.burns);
558
+ return {
559
+ ...simulation,
560
+ curator: sdk.marketRegister.findByPool(pool).curator,
561
+ positionAfter: sdk.pools.sharesToUnderlying(pool, after > 0n ? after : 0n)
562
+ };
563
+ }
564
+ /**
514
565
  * A pool route the market does not offer, as the refusal a caller reads.
515
566
  *
516
567
  * `to` is absent where {@link lpRoute} found no output to name at all, which
@@ -21,6 +21,6 @@ import { amountSchema, assetTypeSchema, bpsSchema, chainIdSchema, leverageSchema
21
21
  import { ChainFailed, ChainMetadata, ChainScoped, ChainSucceeded, DataResponse, DataSource, ResponseMetadata } from "./response.js";
22
22
  import { chainFailedSchema, chainMetadataSchema, chainSucceededSchema, dataSourceSchema, responseMetadataSchema, responseSchema } from "./response.schema.js";
23
23
  import { SDKError, SDKResult, SDKReturn, isSDKError, sdkErr, sdkOk } from "./result.js";
24
- import { PositionClaimableWithdrawal, PositionPendingWithdrawal, PositionWithdrawals } from "./withdrawals.js";
25
- import { positionClaimableWithdrawalSchema, positionPendingWithdrawalSchema, positionWithdrawalsSchema } from "./withdrawals.schema.js";
26
- export { AccountHoldings, AccountMetrics, AccountProjection, AccountStateChange, AdjustStrategyPositionPreview, Amount, ApyBreakdown, Asset, AssetType, BorrowRateBreakdown, Bps, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, ChainFailed, ChainId, ChainMetadata, ChainScoped, ChainScopedFilter, ChainSucceeded, ChartBundle, ChartDenomination, ChartMetric, ChartQuery, ChartRange, ChartSeries, ChartSeriesOk, ChartSeriesUnavailable, ChartUnavailableCode, ChartUnit, ChartValue, ChartWindow, CompareTag, CompareTolerance, CreditOperationMarket, Curator, CuratorName, DataResponse, DataSource, DelayedAddCollateralIntent, DelayedCloseAccountIntent, DelayedDecreaseLeverageIntent, DelayedDepositAndIncreaseLeverageIntent, DelayedDepositIntent, DelayedIncreaseLeverageIntent, DelayedIntent, DelayedReceivedAsset, DelayedStrategyPositionOperationPreview, DelayedWithdrawCollateralIntent, ERROR_ADAPTER_CALL_OUTSIDE_BRACKET, ERROR_INVALID_TRANSACTION_VALUE, ERROR_MALFORMED_BRACKET, ERROR_NON_ADAPTER_CALL_IN_BRACKET, ERROR_UNPREVIEWABLE_ADAPTER_CALL, ERROR_UNPRICEABLE_TOKEN, ERROR_UNSUPPORTED_OUT_OF_BRACKET_CALL, Estimated, EstimatedProjection, ExitStrategyPositionPreview, FILTER_ALL, FilterAll, Filterable, GridSampling, IGearboxError, InstantReceivedAsset, InstantStrategyPositionOperationPreview, Leverage, LiquidatableAccount, LiquidatableAccountFilter, LiquidationApproval, LiquidationDetails, LiquidationPosition, Notice, NoticeKind, NoticeSubject, OpenStrategyPositionPreview, OperationPreview, OperationPreviewError, Opportunity, OpportunityBase, OpportunityChartMetric, OpportunityDetail, OpportunityFilter, OpportunityId, OpportunityKey, OpportunityKind, OpportunityTotals, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PnlBreakdown, PointRewards, PointsProgram, PointsProgramPnL, PointsRewardsPnL, PoolOperationType, PoolOpportunity, PoolOpportunityChartMetric, PoolOpportunityDetail, PoolOpportunityKey, PoolOpportunityRef, PoolPosition, PoolPositionChartMetric, PoolPositionKey, PoolPositionOperationPreview, PoolPositionRef, Position, PositionChartMetric, PositionClaimableWithdrawal, PositionCollateral, PositionFilter, PositionId, PositionKey, PositionKind, PositionPendingWithdrawal, PositionTransaction, PositionTransactionKind, PositionWithdrawals, PositionsTotals, PreviewOperationInput, PreviewOperationOptions, PriceFeedData, PriceFeedSummary, QuotaAsset, RateCurve, RateCurvePoint, ReceivedAsset, RepayStrategyPositionPreview, ResponseMetadata, Rewards, RewardsPnL, RoutedField, SDKError, SDKResult, SDKReturn, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, StrategyOpportunity, StrategyOpportunityChartMetric, StrategyOpportunityDetail, StrategyOpportunityKey, StrategyOpportunityRef, StrategyPosition, StrategyPositionChartMetric, StrategyPositionKey, StrategyPositionRef, Timestamp, Token, TokenAmount, TokenQuotaRate, TokenRewards, TokenRewardsPnL, ToleranceCompareTag, TxCall, UnderlyingToken, amountSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, curatorNameSchema, curatorSchema, dataSourceSchema, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, instantReceivedAssetSchema, isFilterSet, isSDKError, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema };
24
+ import { PositionClaimableWithdrawal, PositionPendingWithdrawal, PositionWithdrawals, WithdrawalOutputAmount } from "./withdrawals.js";
25
+ import { positionClaimableWithdrawalSchema, positionPendingWithdrawalSchema, positionWithdrawalsSchema, withdrawalOutputAmountSchema } from "./withdrawals.schema.js";
26
+ export { AccountHoldings, AccountMetrics, AccountProjection, AccountStateChange, AdjustStrategyPositionPreview, Amount, ApyBreakdown, Asset, AssetType, BorrowRateBreakdown, Bps, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, ChainFailed, ChainId, ChainMetadata, ChainScoped, ChainScopedFilter, ChainSucceeded, ChartBundle, ChartDenomination, ChartMetric, ChartQuery, ChartRange, ChartSeries, ChartSeriesOk, ChartSeriesUnavailable, ChartUnavailableCode, ChartUnit, ChartValue, ChartWindow, CompareTag, CompareTolerance, CreditOperationMarket, Curator, CuratorName, DataResponse, DataSource, DelayedAddCollateralIntent, DelayedCloseAccountIntent, DelayedDecreaseLeverageIntent, DelayedDepositAndIncreaseLeverageIntent, DelayedDepositIntent, DelayedIncreaseLeverageIntent, DelayedIntent, DelayedReceivedAsset, DelayedStrategyPositionOperationPreview, DelayedWithdrawCollateralIntent, ERROR_ADAPTER_CALL_OUTSIDE_BRACKET, ERROR_INVALID_TRANSACTION_VALUE, ERROR_MALFORMED_BRACKET, ERROR_NON_ADAPTER_CALL_IN_BRACKET, ERROR_UNPREVIEWABLE_ADAPTER_CALL, ERROR_UNPRICEABLE_TOKEN, ERROR_UNSUPPORTED_OUT_OF_BRACKET_CALL, Estimated, EstimatedProjection, ExitStrategyPositionPreview, FILTER_ALL, FilterAll, Filterable, GridSampling, IGearboxError, InstantReceivedAsset, InstantStrategyPositionOperationPreview, Leverage, LiquidatableAccount, LiquidatableAccountFilter, LiquidationApproval, LiquidationDetails, LiquidationPosition, Notice, NoticeKind, NoticeSubject, OpenStrategyPositionPreview, OperationPreview, OperationPreviewError, Opportunity, OpportunityBase, OpportunityChartMetric, OpportunityDetail, OpportunityFilter, OpportunityId, OpportunityKey, OpportunityKind, OpportunityTotals, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PnlBreakdown, PointRewards, PointsProgram, PointsProgramPnL, PointsRewardsPnL, PoolOperationType, PoolOpportunity, PoolOpportunityChartMetric, PoolOpportunityDetail, PoolOpportunityKey, PoolOpportunityRef, PoolPosition, PoolPositionChartMetric, PoolPositionKey, PoolPositionOperationPreview, PoolPositionRef, Position, PositionChartMetric, PositionClaimableWithdrawal, PositionCollateral, PositionFilter, PositionId, PositionKey, PositionKind, PositionPendingWithdrawal, PositionTransaction, PositionTransactionKind, PositionWithdrawals, PositionsTotals, PreviewOperationInput, PreviewOperationOptions, PriceFeedData, PriceFeedSummary, QuotaAsset, RateCurve, RateCurvePoint, ReceivedAsset, RepayStrategyPositionPreview, ResponseMetadata, Rewards, RewardsPnL, RoutedField, SDKError, SDKResult, SDKReturn, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, StrategyOpportunity, StrategyOpportunityChartMetric, StrategyOpportunityDetail, StrategyOpportunityKey, StrategyOpportunityRef, StrategyPosition, StrategyPositionChartMetric, StrategyPositionKey, StrategyPositionRef, Timestamp, Token, TokenAmount, TokenQuotaRate, TokenRewards, TokenRewardsPnL, ToleranceCompareTag, TxCall, UnderlyingToken, WithdrawalOutputAmount, amountSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, curatorNameSchema, curatorSchema, dataSourceSchema, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, instantReceivedAssetSchema, isFilterSet, isSDKError, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, withdrawalOutputAmountSchema };
@@ -2,6 +2,21 @@ import { Timestamp, Token, TokenAmount, TxCall } from "./primitives.js";
2
2
  import { DelayedIntent } from "./delayed-intents.js";
3
3
  import { Address } from "viem";
4
4
  //#region src/model/withdrawals.d.ts
5
+ /**
6
+ * One token amount a delayed withdrawal produces, and when.
7
+ **/
8
+ interface WithdrawalOutputAmount extends TokenAmount {
9
+ /**
10
+ * `false` when the amount lands on the credit account as the withdrawal is
11
+ * requested or claimed. `true` when it does not: the token is then the
12
+ * withdrawal phantom standing for a part that has not matured, and another
13
+ * claim is needed for it.
14
+ *
15
+ * A withdrawal that produces both at once is a legacy Mellow multivault: it
16
+ * serves whatever its subvaults hold liquid and queues the remainder.
17
+ **/
18
+ isDelayed: boolean;
19
+ }
5
20
  /**
6
21
  * A delayed withdrawal of a strategy position that has matured and can be claimed.
7
22
  **/
@@ -16,9 +31,12 @@ interface PositionClaimableWithdrawal {
16
31
  **/
17
32
  withdrawalPhantomToken: TokenAmount;
18
33
  /**
19
- * Tokens received by the credit account upon claiming.
34
+ * What the claim credits the account with. Everything a venue that answers
35
+ * whole produces lands at once; one that pays in instalments credits part of
36
+ * it as a fresh withdrawal position, see
37
+ * {@link WithdrawalOutputAmount.isDelayed}.
20
38
  **/
21
- outputs: TokenAmount[];
39
+ outputs: WithdrawalOutputAmount[];
22
40
  /**
23
41
  * Adapter call that executes the claim. Subcompressors always report exactly
24
42
  * one call; it is wrapped into a facade multicall by `assembleClaimDelayedCalls`.
@@ -50,9 +68,10 @@ interface PositionPendingWithdrawal {
50
68
  withdrawalPhantomToken: Token;
51
69
  /**
52
70
  * Estimated tokens the position will receive once the withdrawal
53
- * matures and is claimed.
71
+ * matures and is claimed, see {@link WithdrawalOutputAmount.isDelayed} for
72
+ * the ones a single claim will not bring.
54
73
  **/
55
- expectedOutputs: TokenAmount[];
74
+ expectedOutputs: WithdrawalOutputAmount[];
56
75
  /**
57
76
  * Unix timestamp (in seconds) when the withdrawal becomes claimable.
58
77
  **/
@@ -84,4 +103,4 @@ interface PositionWithdrawals {
84
103
  pending: PositionPendingWithdrawal[];
85
104
  }
86
105
  //#endregion
87
- export { PositionClaimableWithdrawal, PositionPendingWithdrawal, PositionWithdrawals };
106
+ export { PositionClaimableWithdrawal, PositionPendingWithdrawal, PositionWithdrawals, WithdrawalOutputAmount };