@gearbox-protocol/sdk 16.0.0-next.44 → 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 (51) 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/market/adapters/contracts/BalancerV3RouterAdapterContract.js +33 -1
  6. package/dist/cjs/onchain/pools/PoolService.js +20 -4
  7. package/dist/cjs/onchain/positions/PositionsService.js +8 -2
  8. package/dist/cjs/sdk/prepare/PrepareApi.js +133 -82
  9. package/dist/esm/dev/AccountOpener.js +1 -1
  10. package/dist/esm/dev/withdrawalUtils.js +1 -1
  11. package/dist/esm/model/index.js +2 -2
  12. package/dist/esm/model/withdrawals.schema.js +7 -3
  13. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +2 -2
  14. package/dist/esm/onchain/accounts/intents/index.js +38 -13
  15. package/dist/esm/onchain/accounts/intents/tail.js +112 -5
  16. package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +1 -1
  17. package/dist/esm/onchain/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
  18. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
  19. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
  20. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  21. package/dist/esm/onchain/base/TokensMeta.js +3 -3
  22. package/dist/esm/onchain/core/createAddressProvider.js +1 -1
  23. package/dist/esm/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
  24. package/dist/esm/onchain/market/adapters/contracts/BalancerV3RouterAdapterContract.js +33 -1
  25. package/dist/esm/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
  26. package/dist/esm/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
  27. package/dist/esm/onchain/market/pool/PoolV310Contract.js +1 -1
  28. package/dist/esm/onchain/market/zapper/IETHZapperContract.js +1 -1
  29. package/dist/esm/onchain/market/zapper/ZapperContract.js +1 -1
  30. package/dist/esm/onchain/pools/PoolService.js +20 -4
  31. package/dist/esm/onchain/positions/PositionsService.js +8 -2
  32. package/dist/esm/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
  33. package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
  34. package/dist/esm/preview/trace/extractTransfers.js +1 -1
  35. package/dist/esm/sdk/prepare/PrepareApi.js +133 -82
  36. package/dist/types/model/index.d.ts +3 -3
  37. package/dist/types/model/withdrawals.d.ts +24 -5
  38. package/dist/types/model/withdrawals.schema.d.ts +21 -1
  39. package/dist/types/onchain/accounts/index.d.ts +2 -2
  40. package/dist/types/onchain/accounts/intents/index.d.ts +19 -11
  41. package/dist/types/onchain/accounts/intents/tail.d.ts +13 -3
  42. package/dist/types/onchain/accounts/intents/types.d.ts +74 -1
  43. package/dist/types/onchain/index.d.ts +3 -3
  44. package/dist/types/onchain/pools/PoolService.d.ts +10 -1
  45. package/dist/types/onchain/pools/index.d.ts +2 -2
  46. package/dist/types/onchain/pools/types.d.ts +40 -1
  47. package/dist/types/sdk/index.d.ts +3 -3
  48. package/dist/types/sdk/prepare/PrepareApi.d.ts +8 -7
  49. package/dist/types/sdk/prepare/index.d.ts +3 -3
  50. package/dist/types/sdk/prepare/types.d.ts +85 -28
  51. package/package.json +1 -1
@@ -155,3 +155,4 @@ exports.tokenSchema = require_model_primitives_schema.tokenSchema;
155
155
  exports.tolerance = require_model_compare_schema.tolerance;
156
156
  exports.txCallSchema = require_model_primitives_schema.txCallSchema;
157
157
  exports.underlyingTokenSchema = require_model_primitives_schema.underlyingTokenSchema;
158
+ exports.withdrawalOutputAmountSchema = require_model_withdrawals_schema.withdrawalOutputAmountSchema;
@@ -5,12 +5,16 @@ const require_model_delayed_intent_schema = require("./delayed-intent.schema.js"
5
5
  let zod_v4 = require("zod/v4");
6
6
  //#region src/model/withdrawals.schema.ts
7
7
  /**
8
+ * {@link WithdrawalOutputAmount}
9
+ **/
10
+ const withdrawalOutputAmountSchema = require_model_primitives_schema.tokenAmountSchema.extend({ isDelayed: zod_v4.z.boolean() });
11
+ /**
8
12
  * {@link PositionClaimableWithdrawal}
9
13
  **/
10
14
  const positionClaimableWithdrawalSchema = zod_v4.z.object({
11
15
  sourceToken: require_model_primitives_schema.tokenSchema,
12
16
  withdrawalPhantomToken: require_model_primitives_schema.tokenAmountSchema,
13
- outputs: zod_v4.z.array(require_model_primitives_schema.tokenAmountSchema),
17
+ outputs: zod_v4.z.array(withdrawalOutputAmountSchema),
14
18
  claimCall: require_model_primitives_schema.txCallSchema,
15
19
  redeemer: require_onchain_utils_zod.ZodAddress().optional(),
16
20
  intent: require_model_delayed_intent_schema.delayedIntentSchema.optional()
@@ -21,7 +25,7 @@ const positionClaimableWithdrawalSchema = zod_v4.z.object({
21
25
  const positionPendingWithdrawalSchema = zod_v4.z.object({
22
26
  sourceToken: require_model_primitives_schema.tokenSchema,
23
27
  withdrawalPhantomToken: require_model_primitives_schema.tokenSchema,
24
- expectedOutputs: zod_v4.z.array(require_model_primitives_schema.tokenAmountSchema),
28
+ expectedOutputs: zod_v4.z.array(withdrawalOutputAmountSchema),
25
29
  claimableAt: require_model_primitives_schema.timestampSchema,
26
30
  redeemer: require_onchain_utils_zod.ZodAddress().optional(),
27
31
  intent: require_model_delayed_intent_schema.delayedIntentSchema.optional()
@@ -37,3 +41,4 @@ const positionWithdrawalsSchema = zod_v4.z.object({
37
41
  exports.positionClaimableWithdrawalSchema = positionClaimableWithdrawalSchema;
38
42
  exports.positionPendingWithdrawalSchema = positionPendingWithdrawalSchema;
39
43
  exports.positionWithdrawalsSchema = positionWithdrawalsSchema;
44
+ exports.withdrawalOutputAmountSchema = withdrawalOutputAmountSchema;
@@ -46,21 +46,27 @@ var CreditAccountOperationsService = class extends require_onchain_base_SDKConst
46
46
  }));
47
47
  }
48
48
  /**
49
- * Largest `WITHDRAW` amount (in underlying) the account can take out while
50
- * keeping leverage and staying inside the facade's debt band — the ceiling a
51
- * withdraw form should offer. Taking everything out is the same intent with
52
- * `MAX_UINT256` for an amount, and needs none of this arithmetic.
49
+ * Both ends of what a `WITHDRAW` can take out, in underlying: the largest
50
+ * partial withdrawal that keeps leverage and stays inside the facade's debt
51
+ * band, and the net value an exit hands over. They are reported together
52
+ * because a withdraw form needs both the range it may offer, and the one
53
+ * amount past it that is allowed — and because the distance between them is
54
+ * the account's own, not a constant a caller could assume.
53
55
  *
54
56
  * Takes no target health factor, unlike {@link maxWithdrawCollateral}: a
55
57
  * proportional withdrawal leaves the factor where it found it, and the
56
58
  * facade's `minDebt` is what bounds it.
57
59
  *
58
60
  * @param props - Account slice and the SDK holding its market
59
- * @returns Amount in underlying units; `0n` when nothing can leave
61
+ * @returns The two ceilings, see {@link WithdrawCeilings} for the gap between
62
+ * them
60
63
  */
61
64
  maxWithdraw(props) {
62
65
  const view = require_onchain_accounts_intents_view.accountView(props.creditAccount, props.sdk);
63
- return require_onchain_accounts_intents_math.maxProportionalWithdrawal(view, view.band);
66
+ return {
67
+ partial: require_onchain_accounts_intents_math.maxProportionalWithdrawal(view, view.band),
68
+ exit: view.collateral > 0n ? view.collateral : 0n
69
+ };
64
70
  }
65
71
  /**
66
72
  * Debt a `REPAY` would have to cover to settle the account, in underlying
@@ -230,17 +236,36 @@ var CreditAccountOperationsService = class extends require_onchain_base_SDKConst
230
236
  * whole tail: the tokens land on the account and only their quota has to
231
237
  * catch up.
232
238
  *
239
+ * A claim that brought only part of what the request queued — a legacy Mellow
240
+ * multivault, which pays out what it holds liquid and re-queues the rest — is
241
+ * served in proportion, and what it did not settle comes back as `remainder`:
242
+ * the withdrawal still in flight and the intent to finish it with.
243
+ *
233
244
  * @param props - The recorded intent, the account slice as it stands now, and
234
245
  * the matured claimable
235
- * @returns Shaped exactly like {@link startIntent}'s result, so both halves of
236
- * an operation are consumed the same way
246
+ * @returns Shaped exactly like {@link startIntent}'s result with the remainder
247
+ * beside it, so both halves of an operation are consumed the same way
237
248
  */
238
249
  async finishIntent(props) {
239
- return plain(await this.#preview(props, () => require_onchain_accounts_intents_tail.planTail({
240
- intent: props.intent,
241
- claimable: props.claimable,
242
- view: require_onchain_accounts_intents_view.accountView(props.creditAccount, props.sdk)
243
- })));
250
+ let remainder;
251
+ const result = await this.#preview(props, () => {
252
+ const tail = require_onchain_accounts_intents_tail.planTail({
253
+ intent: props.intent,
254
+ claimable: props.claimable,
255
+ view: require_onchain_accounts_intents_view.accountView(props.creditAccount, props.sdk)
256
+ });
257
+ remainder = tail.remainder;
258
+ return tail.steps;
259
+ });
260
+ if (!result.ok) return result;
261
+ const { operations, state, calls } = result;
262
+ return {
263
+ ok: true,
264
+ operations,
265
+ state,
266
+ calls,
267
+ remainder
268
+ };
244
269
  }
245
270
  /**
246
271
  * Previews opening a brand-new leveraged position.
@@ -1,5 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_validation_refusal = require("../../validation/refusal.js");
3
+ const require_onchain_validation_token = require("../../validation/token.js");
4
+ const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
3
5
  const require_onchain_accounts_intents_utils_router_path = require("./utils/router-path.js");
4
6
  const require_onchain_accounts_intents_plan = require("./plan.js");
5
7
  const require_onchain_accounts_intents_operations = require("./operations.js");
@@ -13,6 +15,10 @@ const require_onchain_accounts_intents_view = require("./view.js");
13
15
  * Shared by the two callers that need it and must not disagree — the tail as
14
16
  * it is previewed days later against the account that really exists, and the
15
17
  * tail as it is projected the moment the request is made.
18
+ *
19
+ * A claim that brought only part of what was queued is served in proportion,
20
+ * see {@link partialTail}: the intent's payout and its repayment are cut to the
21
+ * share that arrived, and the rest of both is handed to the next claim.
16
22
  */
17
23
  function planTail(args) {
18
24
  const { intent, claimable, view } = args;
@@ -21,17 +27,118 @@ function planTail(args) {
21
27
  if (!output) throw new require_onchain_validation_refusal.IntentPreviewError("insufficientSourceBalance", void 0, "finishIntent: the claim credits nothing to spend");
22
28
  return output;
23
29
  };
30
+ const queued = claimable.outputs.find((o) => o.isDelayed && o.amount > 0n);
31
+ if (queued) return partialTail({
32
+ intent,
33
+ claimable,
34
+ queued,
35
+ view
36
+ });
24
37
  switch (intent.type) {
25
- case "WITHDRAW_COLLATERAL": return require_onchain_accounts_intents_plan.planFinishWithdraw(intent, claimable, claimed(), view);
26
- case "DECREASE_LEVERAGE": return require_onchain_accounts_intents_plan.planFinishDecreaseLeverage(claimable, claimed(), view);
27
- case "CLOSE_ACCOUNT": return require_onchain_accounts_intents_plan.planFinishCloseAccount(intent, claimable, claimed(), view);
38
+ case "WITHDRAW_COLLATERAL": return whole(require_onchain_accounts_intents_plan.planFinishWithdraw(intent, claimable, claimed(), view));
39
+ case "DECREASE_LEVERAGE": return whole(require_onchain_accounts_intents_plan.planFinishDecreaseLeverage(claimable, claimed(), view));
40
+ case "CLOSE_ACCOUNT": return whole(require_onchain_accounts_intents_plan.planFinishCloseAccount(intent, claimable, claimed(), view));
28
41
  case "ADD_COLLATERAL":
29
42
  case "INCREASE_LEVERAGE":
30
43
  case "DEPOSIT":
31
- case "DEPOSIT_AND_INCREASE_LEVERAGE": return require_onchain_accounts_intents_plan.planFinishClaimOnly(claimable);
44
+ case "DEPOSIT_AND_INCREASE_LEVERAGE": return whole(require_onchain_accounts_intents_plan.planFinishClaimOnly(claimable));
32
45
  default: throw new Error(`${intent.type} - not implemented`);
33
46
  }
34
47
  }
48
+ const whole = (steps) => ({
49
+ steps,
50
+ remainder: void 0
51
+ });
52
+ /**
53
+ * The tail of a claim that settled only part of the withdrawal it matured.
54
+ *
55
+ * Only a legacy Mellow multivault answers one this way — it pays out what its
56
+ * subvaults hold liquid and queues the rest — and the engine cannot finish an
57
+ * intent it has been given a fraction of the funds for. So the fraction is what
58
+ * it serves: the payout and the repayment are cut in the proportion that
59
+ * arrived, which keeps the withdrawal at the fixed leverage it was asked for
60
+ * instead of paying the wallet out first and deleveraging a claim later, and
61
+ * the untouched half of each is carried to the next claim by the remainder.
62
+ *
63
+ * Two intents cannot be served in part at all. An exit sells the account whole,
64
+ * and it cannot while a withdrawal is in flight — the phantom is neither
65
+ * sellable nor transferable — so a partial claim only repays what it brought
66
+ * and the account is emptied by the claim that brings the last of it. A claim
67
+ * that credited nothing at all leaves nothing to spend, so it is taken alone:
68
+ * it is still worth sending, since it is what moves the queue.
69
+ */
70
+ function partialTail(args) {
71
+ const { intent, claimable, queued, view } = args;
72
+ const inFlight = require_onchain_validation_token.toTokenAmount(view.sdk, queued.token, queued.amount);
73
+ const claimed = require_onchain_accounts_intents_operations.instantOutput(claimable.outputs);
74
+ if (!claimed) return {
75
+ steps: require_onchain_accounts_intents_plan.planFinishClaimOnly(claimable),
76
+ remainder: {
77
+ inFlight,
78
+ intent
79
+ }
80
+ };
81
+ switch (intent.type) {
82
+ case "WITHDRAW_COLLATERAL": {
83
+ const served = arrivedShare(claimed, queued, view.sdk);
84
+ const withdrawAmount = part(intent.withdrawAmount, served);
85
+ const debtRepaid = part(intent.debtRepaid, served);
86
+ return {
87
+ steps: require_onchain_accounts_intents_plan.planFinishWithdraw({
88
+ ...intent,
89
+ withdrawAmount,
90
+ debtRepaid
91
+ }, claimable, claimed, view),
92
+ remainder: {
93
+ inFlight,
94
+ intent: {
95
+ ...intent,
96
+ withdrawAmount: intent.withdrawAmount - withdrawAmount,
97
+ debtRepaid: intent.debtRepaid - debtRepaid
98
+ }
99
+ }
100
+ };
101
+ }
102
+ case "DECREASE_LEVERAGE":
103
+ case "CLOSE_ACCOUNT": return {
104
+ steps: require_onchain_accounts_intents_plan.planFinishDecreaseLeverage(claimable, claimed, view),
105
+ remainder: {
106
+ inFlight,
107
+ intent
108
+ }
109
+ };
110
+ case "ADD_COLLATERAL":
111
+ case "INCREASE_LEVERAGE":
112
+ case "DEPOSIT":
113
+ case "DEPOSIT_AND_INCREASE_LEVERAGE": return {
114
+ steps: require_onchain_accounts_intents_plan.planFinishClaimOnly(claimable),
115
+ remainder: {
116
+ inFlight,
117
+ intent
118
+ }
119
+ };
120
+ default: throw new Error(`${intent.type} - not implemented`);
121
+ }
122
+ }
123
+ /**
124
+ * How much of the redemption this claim was: what it credited, over that plus
125
+ * what it left queued.
126
+ *
127
+ * The phantom stands for its payout one for one — the same reading the request
128
+ * side takes when it names the claim it expects — so only the decimals of the
129
+ * two have to be reconciled before they can be added up.
130
+ */
131
+ function arrivedShare(claimed, queued, sdk) {
132
+ const rest = require_onchain_accounts_intents_utils_common.toTargetDecimals(queued.amount, queued.token, claimed.token, sdk);
133
+ return {
134
+ got: claimed.amount,
135
+ of: claimed.amount + rest
136
+ };
137
+ }
138
+ /** A share of an amount, rounded down: a tail never promises more than it has. */
139
+ function part(amount, share) {
140
+ return share.of > 0n ? amount * share.got / share.of : 0n;
141
+ }
35
142
  /**
36
143
  * Where a delayed intent ends up, worked out at the moment it is started.
37
144
  *
@@ -56,7 +163,7 @@ async function projectTail(args) {
56
163
  const queued = request.outputs.find((o) => o.isDelayed);
57
164
  if (!queued || !claim) throw new require_onchain_validation_refusal.IntentPreviewError("noRecordedIntent", void 0, "projectTail: the request queued nothing to claim");
58
165
  const next = sliceAfter(creditAccount, delayed.afterRequest);
59
- const steps = planTail({
166
+ const { steps } = planTail({
60
167
  intent: delayed.record,
61
168
  claimable: projectedClaimable(request, queued.token, queued.amount, claim),
62
169
  view: require_onchain_accounts_intents_view.accountView(next, sdk)
@@ -1,4 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_onchain_utils_AddressMap = require("../../../utils/AddressMap.js");
3
+ require("../../../utils/index.js");
2
4
  const require_onchain_base_errors = require("../../../base/errors.js");
3
5
  require("../../../base/index.js");
4
6
  const require_onchain_market_adapters_abi_adapters_iBalancerV3RouterAdapter = require("../abi/adapters/iBalancerV3RouterAdapter.js");
@@ -7,6 +9,30 @@ const require_onchain_market_adapters_abi_targetContractAbi = require("../abi/ta
7
9
  const require_onchain_market_adapters_contracts_AbstractAdapter = require("./AbstractAdapter.js");
8
10
  let viem = require("viem");
9
11
  //#region src/onchain/market/adapters/contracts/BalancerV3RouterAdapterContract.ts
12
+ const BALANCER_V3_POOL_TOKENS = {
13
+ Mainnet: new require_onchain_utils_AddressMap.AddressMap([
14
+ ["0x121edB0bADc036F5FC610D015EE14093C142313B", ["0x775F661b0bD1739349b9A2A3EF60be277c5d2D29", "0x7a4EffD87C2f3C55CA251080b1343b605f327E3a"]],
15
+ ["0x1ea5870f7C037930CE1d5d8d9317c670e89e13E3", ["0x0bfc9d54Fc184518A81162F8fB99c2eACa081202", "0xae78736Cd615f374D3085123A210448E74Fc6393"]],
16
+ ["0x57c23c58B1D8C3292c15BEcF07c62C5c52457A42", ["0x0bfc9d54Fc184518A81162F8fB99c2eACa081202", "0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38"]],
17
+ ["0x6b31a94029fd7840d780191B6D63Fa0D269bd883", ["0x2411802D8BEA09be0aF8fD8D08314a63e706b29C", "0x90551c1795392094FE6D29B758EcCD233cFAa260"]],
18
+ ["0x85B2b559bC2D21104C4DEFdd6EFcA8A20343361D", [
19
+ "0x7Bc3485026Ac48b6cf9BaF0A377477Fff5703Af8",
20
+ "0xC71Ea051a5F82c67ADcF634c36FFE6334793D24C",
21
+ "0xD4fa2D31b7968E448877f69A96DE69f5de8cD23E"
22
+ ]],
23
+ ["0x9ED5175aeCB6653C1BDaa19793c16fd74fBeEB37", ["0x775F661b0bD1739349b9A2A3EF60be277c5d2D29", "0xD11c452fc99cF405034ee446803b6F6c1F6d5ED8"]],
24
+ ["0xc4Ce391d82D164c166dF9c8336DDF84206b2F812", ["0x0FE906e030a44eF24CA8c7dC7B7c53A6C4F00ce9", "0x775F661b0bD1739349b9A2A3EF60be277c5d2D29"]]
25
+ ]),
26
+ Plasma: new require_onchain_utils_AddressMap.AddressMap([
27
+ ["0x01E2C7fCde2B8D5d1413732c4e274Ba5B06B1E54", ["0x0A1a1A107E45b7Ced86833863f482BC5f4ed82EF", "0xE0126F0c4451B2B917064A93040fd4770D6774b5"]],
28
+ ["0x694c009aa31B3F80EE18C218B02390ca2D7151e7", ["0x6eAf19b2FC24552925dB245F9Ff613157a7dbb4C", "0xE0126F0c4451B2B917064A93040fd4770D6774b5"]],
29
+ ["0x6a74BE33B5393D8A3EbA4D69B78f9D9da947C48c", ["0xC63F1a8c0cD4493E18f6f3371182BE01Ce0BeF02", "0xE0126F0c4451B2B917064A93040fd4770D6774b5"]],
30
+ ["0xB3Ca3ead1c59dEd552cD30a6992038284B418b65", ["0x0B2b2B2076d95dda7817e785989fE353fe955ef9", "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"]],
31
+ ["0xD931775d9AcA9859c9fDc53C63ae32EF21551492", ["0x9c46EE1f01d2b551048F5fF99a4659D98d04BED1", "0xC8A8DF9B210243c55D31c73090F06787aD0A1Bf6"]],
32
+ ["0xd9c4e277c93374a9f8C877a9D06707a88092E8F0", ["0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2", "0xE0126F0c4451B2B917064A93040fd4770D6774b5"]],
33
+ ["0xDE0cfD933D2036d99048a04acF5Bacfb45492377", ["0x76309A9a56309104518847BbA321c261B7B4a43f", "0xA29420057F3e3B9512D4786df135Da1674BD74D4"]]
34
+ ])
35
+ };
10
36
  let BalancerV3PoolStatus = /* @__PURE__ */ function(BalancerV3PoolStatus) {
11
37
  BalancerV3PoolStatus[BalancerV3PoolStatus["NOT_ALLOWED"] = 0] = "NOT_ALLOWED";
12
38
  BalancerV3PoolStatus[BalancerV3PoolStatus["ALLOWED"] = 1] = "ALLOWED";
@@ -99,7 +125,13 @@ var BalancerV3RouterAdapterContract = class extends require_onchain_market_adapt
99
125
  this.setLeftover(balances, pool, leftoverAmount);
100
126
  break;
101
127
  }
102
- case "addLiquidityUnbalancedDiff": throw new Error(`previewBalanceChanges cannot resolve pool tokens for addLiquidityUnbalancedDiff on ${this.contractType} adapter at ${this.address}`);
128
+ case "addLiquidityUnbalancedDiff": {
129
+ const [pool, leftoverAmounts] = decoded.args;
130
+ const tokens = BALANCER_V3_POOL_TOKENS[this.networkType]?.get(pool);
131
+ if (!tokens || tokens.length !== leftoverAmounts.length) throw new Error(`previewBalanceChanges cannot resolve pool tokens for addLiquidityUnbalancedDiff on ${this.contractType} adapter at ${this.address} (pool ${pool})`);
132
+ for (let i = 0; i < leftoverAmounts.length; i++) this.setLeftover(balances, tokens[i], leftoverAmounts[i]);
133
+ break;
134
+ }
103
135
  default: super.applyBalanceChanges(balances, decoded);
104
136
  }
105
137
  }
@@ -30,6 +30,25 @@ function payoutCeiling(market) {
30
30
  return market.priceOracle.toAmount(pool.underlying, pool.pool.availableLiquidity * LIQUIDITY_SAFETY_NUM / LIQUIDITY_SAFETY_DENOM);
31
31
  }
32
32
  var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
33
+ /**
34
+ * {@inheritDoc IPoolsService.getShareBalance}
35
+ */
36
+ async getShareBalance(props) {
37
+ return this.client.readContract({
38
+ address: this.sdk.marketRegister.findByPool(props.pool).pool.pool.address,
39
+ abi: require_abi_iERC20.ierc20Abi,
40
+ functionName: "balanceOf",
41
+ args: [props.wallet],
42
+ blockNumber: props.blockNumber
43
+ });
44
+ }
45
+ /**
46
+ * {@inheritDoc IPoolsService.sharesToUnderlying}
47
+ */
48
+ sharesToUnderlying(pool, shares) {
49
+ const market = this.sdk.marketRegister.findByPool(pool);
50
+ return market.toUnderlyingAmount(shares * market.pool.pool.dieselRate / require_onchain_constants_math.RAY);
51
+ }
33
52
  /**
34
53
  * {@inheritDoc IPoolsService.getDepositTokensIn}
35
54
  */
@@ -415,10 +434,7 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
415
434
  chainId: this.chainId,
416
435
  pool: pool.address,
417
436
  underlyingToken: market.underlyingToken,
418
- netValue: {
419
- token: this.sdk.tokensMeta.mustGetToken(market.unwrappedUnderlying),
420
- ...market.priceOracle.toAmount(market.underlying, shares * pool.dieselRate / require_onchain_constants_math.RAY)
421
- },
437
+ netValue: this.sharesToUnderlying(pool.address, shares),
422
438
  apy: { organicApy: require_onchain_market_math.rayToBps(pool.supplyRate) }
423
439
  };
424
440
  }
@@ -373,7 +373,10 @@ var PositionsService = class extends require_onchain_base_SDKConstruct.SDKConstr
373
373
  return {
374
374
  sourceToken: this.sdk.tokensMeta.mustGetToken(w.token),
375
375
  withdrawalPhantomToken: priceOracle.toTokenAmount(w.withdrawalPhantomToken, w.withdrawalTokenSpent),
376
- outputs: w.outputs.map((o) => priceOracle.toTokenAmount(o.token, o.amount)),
376
+ outputs: w.outputs.map((o) => ({
377
+ ...priceOracle.toTokenAmount(o.token, o.amount),
378
+ isDelayed: o.isDelayed
379
+ })),
377
380
  claimCall: this.#claimTx(w.claimCalls, w.token),
378
381
  redeemer: w.redeemer,
379
382
  intent: w.intent
@@ -383,7 +386,10 @@ var PositionsService = class extends require_onchain_base_SDKConstruct.SDKConstr
383
386
  return {
384
387
  sourceToken: this.sdk.tokensMeta.mustGetToken(w.token),
385
388
  withdrawalPhantomToken: this.sdk.tokensMeta.mustGetToken(w.withdrawalPhantomToken),
386
- expectedOutputs: w.expectedOutputs.map((o) => priceOracle.toTokenAmount(o.token, o.amount)),
389
+ expectedOutputs: w.expectedOutputs.map((o) => ({
390
+ ...priceOracle.toTokenAmount(o.token, o.amount),
391
+ isDelayed: o.isDelayed
392
+ })),
387
393
  claimableAt: Number(w.claimableAt),
388
394
  redeemer: w.redeemer,
389
395
  intent: w.intent
@@ -59,7 +59,7 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
59
59
  }));
60
60
  const creditAccount = await slice(sdk, position.creditAccount);
61
61
  if (!creditAccount) return require_model_result.sdkErr(require_sdk_prepare_errors.creditAccountNotFound(position.creditAccount));
62
- return planned(await service(sdk).finishIntent({
62
+ return finalized(await service(sdk).finishIntent({
63
63
  intent,
64
64
  claimable: toClaimableWithdrawal(params.claimable),
65
65
  creditAccount,
@@ -74,94 +74,106 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
74
74
  /**
75
75
  * {@inheritDoc IOpportunitiesPrepare.deposit}
76
76
  **/
77
- deposit(pool, params) {
78
- const chain = this.sdk.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 require_model_result.sdkOk({
100
- operations: [],
101
- state,
102
- calls: call.calls,
103
- ...stateBlock(chain)
104
- });
77
+ async deposit(pool, params) {
78
+ try {
79
+ const chain = await this.#chain(pool.chainId);
80
+ const { marketRegister, pools } = chain;
81
+ const tokenIn = params.tokenIn ?? marketRegister.findByPool(pool.pool).pool.underlying;
82
+ const tokenOut = lpRoute(params.tokenOut, () => pools.getDepositTokensOut(pool.pool, tokenIn));
83
+ if (!tokenOut) return unroutable(chain, tokenIn, void 0);
84
+ const state = pools.simulateDeposit({
85
+ pool: pool.pool,
86
+ amount: params.amount,
87
+ tokenIn,
88
+ tokenOut
89
+ });
90
+ const call = pools.addLiquidity({
91
+ collateral: {
92
+ token: state.tokenIn.token.address,
93
+ balance: state.tokenIn.value
94
+ },
95
+ pool: pool.pool,
96
+ wallet: params.wallet,
97
+ meta: pools.getDepositMetadata(pool.pool, tokenIn, tokenOut)
98
+ });
99
+ if (!call) return unroutable(chain, tokenIn, tokenOut);
100
+ return require_model_result.sdkOk({
101
+ operations: [],
102
+ state: await lpState(chain, pool.pool, params.wallet, state, { mints: state.tokenOut.value }),
103
+ calls: call.calls,
104
+ ...stateBlock(chain)
105
+ });
106
+ } catch (e) {
107
+ return require_model_result.sdkErr(require_sdk_prepare_errors.unexpectedFailure(e));
108
+ }
105
109
  }
106
110
  /**
107
111
  * {@inheritDoc IOpportunitiesPrepare.withdraw}
108
112
  **/
109
- withdraw(pool, params) {
110
- const chain = this.sdk.chain(pool.chainId);
111
- const { pools } = chain;
112
- const tokenIn = params.tokenIn ?? pool.pool;
113
- const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
114
- if (!tokenOut) return unroutable(chain, tokenIn, void 0);
115
- const state = pools.simulateWithdraw({
116
- pool: pool.pool,
117
- amount: params.amount,
118
- tokenIn,
119
- tokenOut
120
- });
121
- const { calls } = pools.removeLiquidity({
122
- pool: pool.pool,
123
- amount: params.amount,
124
- wallet: params.wallet,
125
- permit: void 0,
126
- meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
127
- mode: "withdraw"
128
- });
129
- return require_model_result.sdkOk({
130
- operations: [],
131
- state,
132
- calls,
133
- ...stateBlock(chain)
134
- });
113
+ async withdraw(pool, params) {
114
+ try {
115
+ const chain = await this.#chain(pool.chainId);
116
+ const { pools } = chain;
117
+ const tokenIn = params.tokenIn ?? pool.pool;
118
+ const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
119
+ if (!tokenOut) return unroutable(chain, tokenIn, void 0);
120
+ const state = pools.simulateWithdraw({
121
+ pool: pool.pool,
122
+ amount: params.amount,
123
+ tokenIn,
124
+ tokenOut
125
+ });
126
+ const { calls } = pools.removeLiquidity({
127
+ pool: pool.pool,
128
+ amount: params.amount,
129
+ wallet: params.wallet,
130
+ permit: void 0,
131
+ meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
132
+ mode: "withdraw"
133
+ });
134
+ return require_model_result.sdkOk({
135
+ operations: [],
136
+ state: await lpState(chain, pool.pool, params.wallet, state, { burns: state.tokenIn.value }),
137
+ calls,
138
+ ...stateBlock(chain)
139
+ });
140
+ } catch (e) {
141
+ return require_model_result.sdkErr(require_sdk_prepare_errors.unexpectedFailure(e));
142
+ }
135
143
  }
136
144
  /**
137
145
  * {@inheritDoc IOpportunitiesPrepare.redeem}
138
146
  **/
139
- redeem(pool, params) {
140
- const chain = this.sdk.chain(pool.chainId);
141
- const { pools } = chain;
142
- const tokenIn = params.tokenIn ?? pool.pool;
143
- const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
144
- if (!tokenOut) return unroutable(chain, tokenIn, void 0);
145
- const state = pools.simulateRedeem({
146
- pool: pool.pool,
147
- amount: params.amount,
148
- tokenIn,
149
- tokenOut
150
- });
151
- const { calls } = pools.removeLiquidity({
152
- pool: pool.pool,
153
- amount: params.amount,
154
- wallet: params.wallet,
155
- permit: void 0,
156
- meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
157
- mode: "redeem"
158
- });
159
- return require_model_result.sdkOk({
160
- operations: [],
161
- state,
162
- calls,
163
- ...stateBlock(chain)
164
- });
147
+ async redeem(pool, params) {
148
+ try {
149
+ const chain = await this.#chain(pool.chainId);
150
+ const { pools } = chain;
151
+ const tokenIn = params.tokenIn ?? pool.pool;
152
+ const tokenOut = lpRoute(params.tokenOut, () => pools.getWithdrawalTokensOut(pool.pool, tokenIn));
153
+ if (!tokenOut) return unroutable(chain, tokenIn, void 0);
154
+ const state = pools.simulateRedeem({
155
+ pool: pool.pool,
156
+ amount: params.amount,
157
+ tokenIn,
158
+ tokenOut
159
+ });
160
+ const { calls } = pools.removeLiquidity({
161
+ pool: pool.pool,
162
+ amount: params.amount,
163
+ wallet: params.wallet,
164
+ permit: void 0,
165
+ meta: pools.getWithdrawalMetadata(pool.pool, tokenIn, tokenOut),
166
+ mode: "redeem"
167
+ });
168
+ return require_model_result.sdkOk({
169
+ operations: [],
170
+ state: await lpState(chain, pool.pool, params.wallet, state, { burns: state.tokenIn.value }),
171
+ calls,
172
+ ...stateBlock(chain)
173
+ });
174
+ } catch (e) {
175
+ return require_model_result.sdkErr(require_sdk_prepare_errors.unexpectedFailure(e));
176
+ }
165
177
  }
166
178
  /**
167
179
  * {@inheritDoc IOpportunitiesPrepare.openNewStrategy}
@@ -413,7 +425,7 @@ function toClaimableWithdrawal(claimable) {
413
425
  outputs: claimable.outputs.map((o) => ({
414
426
  token: o.token.address,
415
427
  amount: o.value,
416
- isDelayed: false
428
+ isDelayed: o.isDelayed
417
429
  })),
418
430
  claimCalls: [{
419
431
  target: claimable.claimCall.to,
@@ -470,6 +482,23 @@ function planned(result, at) {
470
482
  }
471
483
  /**
472
484
  * {@inheritDoc planned}
485
+ *
486
+ * A tail carries one thing the other results do not: whether the claim it was
487
+ * built on finished the withdrawal, or left part of it queued for another one.
488
+ **/
489
+ function finalized(result, at) {
490
+ if (!result.ok) return refusal(result);
491
+ const { operations, state, calls, remainder } = result;
492
+ return require_model_result.sdkOk({
493
+ operations,
494
+ state,
495
+ calls,
496
+ remainder,
497
+ ...at
498
+ });
499
+ }
500
+ /**
501
+ * {@inheritDoc planned}
473
502
  **/
474
503
  function opened(result, at) {
475
504
  return result.ok ? require_model_result.sdkOk({
@@ -512,6 +541,28 @@ function routed(result, at) {
512
541
  });
513
542
  }
514
543
  /**
544
+ * The pool's own numbers as the namespace reports them: the trade the service
545
+ * priced, the market it belongs to, and where the wallet's position lands.
546
+ *
547
+ * The position is measured in shares and converted once, rather than added up
548
+ * in underlying, so the figure is exactly what a later
549
+ * `sdk.positions.list()` will report — the same balance through the same rate.
550
+ * A withdrawal larger than the position floors at nothing: the transaction
551
+ * would revert long before it got there, and a negative holding is not a thing
552
+ * a screen can show.
553
+ **/
554
+ async function lpState(sdk, pool, wallet, simulation, moved) {
555
+ const after = await sdk.pools.getShareBalance({
556
+ pool,
557
+ wallet
558
+ }) + (moved.mints ?? -moved.burns);
559
+ return {
560
+ ...simulation,
561
+ curator: sdk.marketRegister.findByPool(pool).curator,
562
+ positionAfter: sdk.pools.sharesToUnderlying(pool, after > 0n ? after : 0n)
563
+ };
564
+ }
565
+ /**
515
566
  * A pool route the market does not offer, as the refusal a caller reads.
516
567
  *
517
568
  * `to` is absent where {@link lpRoute} found no output to name at all, which
@@ -1,5 +1,5 @@
1
- import { iCreditFacadeV310Abi } from "../abi/310/generated.js";
2
1
  import { ierc20Abi } from "../abi/iERC20.js";
2
+ import { iCreditFacadeV310Abi } from "../abi/310/generated.js";
3
3
  import { AddressMap } from "../onchain/utils/AddressMap.js";
4
4
  import { AddressSet } from "../onchain/utils/AddressSet.js";
5
5
  import { AssetsMap } from "../onchain/utils/AssetsMap.js";
@@ -1,6 +1,6 @@
1
+ import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
1
2
  import { getNetworkType } from "../onchain/chain/chains.js";
2
3
  import { getWithdrawalCompressorAddress } from "../onchain/accounts/withdrawal-compressor/addresses.js";
3
- import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
4
4
  import "../onchain/index.js";
5
5
  import { iMidasDataFeedAbi, iMidasRedemptionVaultAbi, midasGatewayAbi, midasRedeemerAbi, midasRedemptionVaultPhantomTokenAbi, securitizeRedeemerAbi, securitizeRedemptionGatewayAbi, securitizeRedemptionPhantomTokenAbi } from "./withdrawalAbi.js";
6
6
  import { erc20Abi, hexToString, parseAbi, parseEther } from "viem";