@gearbox-protocol/sdk 14.12.0-next.29 → 14.12.0-next.30

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 (39) hide show
  1. package/dist/cjs/preview/preview/CreditAccountState.js +154 -0
  2. package/dist/cjs/preview/preview/buildDelayedPreview.js +111 -0
  3. package/dist/cjs/preview/preview/detectDelayedOperation.js +71 -0
  4. package/dist/cjs/preview/preview/errors.js +17 -0
  5. package/dist/cjs/preview/preview/index.js +10 -4
  6. package/dist/cjs/preview/preview/previewAdjustCreditAccount.js +16 -39
  7. package/dist/cjs/preview/preview/previewCloseOrRepayCreditAccount.js +11 -37
  8. package/dist/cjs/preview/preview/previewOpenCreditAccount.js +13 -8
  9. package/dist/cjs/preview/preview/previewOperation.js +46 -5
  10. package/dist/cjs/preview/preview/{applyInnerOperations.js → replayInnerOperations.js} +24 -35
  11. package/dist/cjs/preview/preview/{applyQuotaChanges.js → replayMulticall.js} +14 -20
  12. package/dist/cjs/preview/preview/types.js +5 -2
  13. package/dist/esm/preview/preview/CreditAccountState.js +133 -0
  14. package/dist/esm/preview/preview/buildDelayedPreview.js +90 -0
  15. package/dist/esm/preview/preview/detectDelayedOperation.js +51 -0
  16. package/dist/esm/preview/preview/errors.js +16 -0
  17. package/dist/esm/preview/preview/index.js +5 -2
  18. package/dist/esm/preview/preview/previewAdjustCreditAccount.js +19 -48
  19. package/dist/esm/preview/preview/previewCloseOrRepayCreditAccount.js +14 -44
  20. package/dist/esm/preview/preview/previewOpenCreditAccount.js +15 -10
  21. package/dist/esm/preview/preview/previewOperation.js +52 -6
  22. package/dist/esm/preview/preview/{applyInnerOperations.js → replayInnerOperations.js} +20 -34
  23. package/dist/esm/preview/preview/replayMulticall.js +16 -0
  24. package/dist/esm/preview/preview/types.js +3 -1
  25. package/dist/types/preview/preview/CreditAccountState.d.ts +83 -0
  26. package/dist/types/preview/preview/buildDelayedPreview.d.ts +41 -0
  27. package/dist/types/preview/preview/detectDelayedOperation.d.ts +29 -0
  28. package/dist/types/preview/preview/errors.d.ts +15 -0
  29. package/dist/types/preview/preview/index.d.ts +5 -2
  30. package/dist/types/preview/preview/previewAdjustCreditAccount.d.ts +3 -3
  31. package/dist/types/preview/preview/previewCloseOrRepayCreditAccount.d.ts +2 -2
  32. package/dist/types/preview/preview/replayInnerOperations.d.ts +44 -0
  33. package/dist/types/preview/preview/replayMulticall.d.ts +38 -0
  34. package/dist/types/preview/preview/types.d.ts +58 -3
  35. package/dist/types/preview/types.d.ts +17 -6
  36. package/package.json +1 -1
  37. package/dist/esm/preview/preview/applyQuotaChanges.js +0 -19
  38. package/dist/types/preview/preview/applyInnerOperations.d.ts +0 -59
  39. package/dist/types/preview/preview/applyQuotaChanges.d.ts +0 -24
@@ -1,27 +1,24 @@
1
- import {
2
- AP_WETH_TOKEN,
3
- NO_VERSION
4
- } from "../../sdk/index.js";
5
- import {
6
- applyInnerOperations,
7
- makeInnerOperationsState
8
- } from "./applyInnerOperations.js";
1
+ import { AP_WETH_TOKEN, NO_VERSION } from "../../sdk/index.js";
9
2
  import { classifyCloseOrRepay } from "./detectCloseOrRepay.js";
3
+ import {
4
+ replayMulticall
5
+ } from "./replayMulticall.js";
10
6
  import { unwrapNativeCollateral } from "./unwrapNativeCollateral.js";
11
7
  async function previewCloseOrRepayCreditAccount(input, operation, permanent, options) {
12
8
  const { sdk } = input;
13
9
  const market = sdk.marketRegister.findByCreditManager(
14
10
  operation.creditManager
15
11
  );
12
+ const replay = await replayMulticall(sdk, operation, options);
16
13
  const kind = classifyCloseOrRepay(operation.multicall, market.underlying);
17
- return kind === "close" ? previewCloseCreditAccount(input, operation, permanent, options) : previewRepayCreditAccount(input, operation, permanent, options);
14
+ return kind === "close" ? previewCloseCreditAccount(input, operation, permanent, replay) : previewRepayCreditAccount(input, operation, permanent, replay);
18
15
  }
19
- async function previewCloseCreditAccount(input, operation, permanent, options) {
16
+ function previewCloseCreditAccount(input, operation, permanent, replay) {
20
17
  const { sdk } = input;
21
18
  const market = sdk.marketRegister.findByCreditManager(
22
19
  operation.creditManager
23
20
  );
24
- const { state, error } = await replayMulticall(sdk, operation, options);
21
+ const { after, error } = replay;
25
22
  return {
26
23
  operation: "CloseCreditAccount",
27
24
  permanent,
@@ -29,59 +26,32 @@ async function previewCloseCreditAccount(input, operation, permanent, options) {
29
26
  creditAccount: operation.creditAccount,
30
27
  // On a malformed multicall the withdrawn amount depends on best-effort
31
28
  // replayed balances and may be unreliable
32
- receivedAmount: state.collateralWithdrawn.getOrZero(market.underlying),
29
+ receivedAmount: after.collateralWithdrawn.getOrZero(market.underlying),
33
30
  error
34
31
  };
35
32
  }
36
- async function previewRepayCreditAccount(input, operation, permanent, options) {
33
+ function previewRepayCreditAccount(input, operation, permanent, replay) {
37
34
  const { sdk, value = 0n } = input;
38
- const {
39
- ca,
40
- state,
41
- error: replayError
42
- } = await replayMulticall(sdk, operation, options);
35
+ const { before, after, error: replayError } = replay;
43
36
  const { assets: collateralAdded, error: unwrapError } = unwrapNativeCollateral(
44
- state.collateralAdded.toAssets(),
37
+ after.collateralAdded.toAssets(),
45
38
  value,
46
39
  sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION)
47
40
  );
48
41
  const error = replayError ?? unwrapError;
49
- const initialTotalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
50
42
  return {
51
43
  operation: "RepayCreditAccount",
52
44
  permanent,
53
45
  creditManager: operation.creditManager,
54
46
  creditAccount: operation.creditAccount,
55
47
  collateralAdded,
56
- debtRepaid: initialTotalDebt - state.totalDebt,
48
+ debtRepaid: before.totalDebt - after.account.totalDebt,
57
49
  // On a malformed multicall the MAX_UINT256 withdrawal sentinel resolves
58
50
  // against best-effort replayed balances and may be unreliable
59
- collateralWithdrawn: state.collateralWithdrawn.toAssets(),
51
+ collateralWithdrawn: after.collateralWithdrawn.toAssets(),
60
52
  error
61
53
  };
62
54
  }
63
- async function replayMulticall(sdk, operation, options) {
64
- let ca = options?.creditAccount;
65
- if (!ca) {
66
- ca = await sdk.accounts.getCreditAccountData(
67
- operation.creditAccount,
68
- options?.blockNumber
69
- );
70
- }
71
- if (!ca) {
72
- throw new Error(`credit account ${operation.creditAccount} not found`);
73
- }
74
- const state = makeInnerOperationsState();
75
- for (const t of ca.tokens) {
76
- if (t.balance > 1n) {
77
- state.balances.upsert(t.token, t.balance);
78
- }
79
- }
80
- state.debt = ca.debt;
81
- state.totalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
82
- const error = await applyInnerOperations(sdk, operation.multicall, state);
83
- return { ca, state, error };
84
- }
85
55
  export {
86
56
  previewCloseOrRepayCreditAccount
87
57
  };
@@ -2,10 +2,11 @@ import {
2
2
  AP_WETH_TOKEN,
3
3
  NO_VERSION
4
4
  } from "../../sdk/index.js";
5
+ import { CreditAccountState } from "./CreditAccountState.js";
5
6
  import {
6
- applyInnerOperations,
7
- makeInnerOperationsState
8
- } from "./applyInnerOperations.js";
7
+ makeReplayState,
8
+ replayInnerOperations
9
+ } from "./replayInnerOperations.js";
9
10
  import {
10
11
  ERROR_UNPRICEABLE_TOKEN
11
12
  } from "./types.js";
@@ -15,8 +16,11 @@ async function previewOpenCreditAccount(input, operation) {
15
16
  const market = sdk.marketRegister.findByCreditManager(
16
17
  operation.creditManager
17
18
  );
18
- const state = makeInnerOperationsState();
19
- let error = await applyInnerOperations(sdk, operation.multicall, state);
19
+ const state = makeReplayState(
20
+ CreditAccountState.beforeOpen(operation.creditManager, market.underlying)
21
+ );
22
+ let error = await replayInnerOperations(sdk, operation.multicall, state);
23
+ const account = state.account;
20
24
  let priceError;
21
25
  const collateralValue = state.collateralAdded.sum((token, balance) => {
22
26
  try {
@@ -35,16 +39,17 @@ async function previewOpenCreditAccount(input, operation) {
35
39
  sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION)
36
40
  );
37
41
  error ??= unwrapError ?? priceError;
38
- const assets = state.balances.toAssets(1n);
42
+ const assets = account.balances.toAssets(1n);
39
43
  return {
40
44
  operation: operation.operation,
41
45
  creditManager: operation.creditManager,
42
- target: inferTargetAsset(operation.multicall, state.balances),
46
+ target: inferTargetAsset(operation.multicall, account.balances),
43
47
  collateral,
44
48
  collateralValue,
45
- debt: state.debt,
46
- // On opening, initial quotas are zero, so the raw changes are the quotas.
47
- quotas: state.quotaChanges,
49
+ debt: account.debt,
50
+ // On opening, initial quotas are zero, so the folded quotas are the
51
+ // applied changes.
52
+ quotas: account.quotas.toAssets(0n),
48
53
  assets,
49
54
  error
50
55
  };
@@ -1,10 +1,18 @@
1
- import { isPoolOperation, parseOperationCalldata } from "../parse/index.js";
1
+ import {
2
+ isPoolOperation,
3
+ parseOperationCalldata
4
+ } from "../parse/index.js";
5
+ import { buildDelayedPreview } from "./buildDelayedPreview.js";
2
6
  import { isCloseOrRepay } from "./detectCloseOrRepay.js";
7
+ import { detectDelayedOperation } from "./detectDelayedOperation.js";
3
8
  import { UnsupportedOperationError } from "./errors.js";
4
9
  import { previewAdjustCreditAccount } from "./previewAdjustCreditAccount.js";
5
10
  import { previewCloseOrRepayCreditAccount } from "./previewCloseOrRepayCreditAccount.js";
6
11
  import { previewOpenCreditAccount } from "./previewOpenCreditAccount.js";
7
12
  import { previewPoolOperation } from "./previewPoolOperation.js";
13
+ import {
14
+ replayMulticall
15
+ } from "./replayMulticall.js";
8
16
  async function previewOperation(input, options) {
9
17
  const operation = parseOperationCalldata(input);
10
18
  if (isPoolOperation(operation)) {
@@ -14,16 +22,54 @@ async function previewOperation(input, options) {
14
22
  return previewOpenCreditAccount(input, operation);
15
23
  }
16
24
  if (operation.operation === "CloseCreditAccount") {
17
- return previewCloseOrRepayCreditAccount(input, operation, true, options);
25
+ const resolved = await resolveCreditAccount(input, operation, options);
26
+ return previewCloseOrRepayCreditAccount(input, operation, true, resolved);
18
27
  }
19
28
  if (operation.operation === "MultiCall" || operation.operation === "BotMulticall" || operation.operation === "RWAMulticall") {
20
- if (isCloseOrRepay(operation.multicall)) {
21
- return previewCloseOrRepayCreditAccount(input, operation, false, options);
22
- }
23
- return previewAdjustCreditAccount(input, operation, options);
29
+ const resolved = await resolveCreditAccount(input, operation, options);
30
+ return previewMulticallOperation(input, operation, resolved);
24
31
  }
25
32
  throw new UnsupportedOperationError(operation.operation);
26
33
  }
34
+ async function resolveCreditAccount(input, operation, options) {
35
+ let creditAccount = options?.creditAccount;
36
+ if (!creditAccount) {
37
+ creditAccount = await input.sdk.accounts.getCreditAccountData(
38
+ operation.creditAccount,
39
+ options?.blockNumber
40
+ );
41
+ }
42
+ if (!creditAccount) {
43
+ throw new Error(`credit account ${operation.creditAccount} not found`);
44
+ }
45
+ return { ...options, creditAccount };
46
+ }
47
+ async function previewMulticallOperation(input, operation, options) {
48
+ const { sdk } = input;
49
+ const instantPreview = isCloseOrRepay(operation.multicall) ? await previewCloseOrRepayCreditAccount(input, operation, false, options) : await previewAdjustCreditAccount(input, operation, options);
50
+ const delayed = detectDelayedOperation(sdk, operation.multicall);
51
+ if (!delayed) {
52
+ return instantPreview;
53
+ }
54
+ const { before, after } = await replayMulticall(sdk, operation, options);
55
+ const market = sdk.marketRegister.findByCreditManager(
56
+ operation.creditManager
57
+ );
58
+ const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
59
+ return {
60
+ operation: "DelayedCreditAccountOperation",
61
+ creditAccount: operation.creditAccount,
62
+ creditManager: operation.creditManager,
63
+ intent: delayed.intent,
64
+ instantPreview,
65
+ delayedPreview: buildDelayedPreview(
66
+ after.account,
67
+ before,
68
+ delayed,
69
+ convert
70
+ )
71
+ };
72
+ }
27
73
  export {
28
74
  previewOperation
29
75
  };
@@ -2,10 +2,7 @@ import {
2
2
  AbstractAdapterContract,
3
3
  ERC4626AdapterContract
4
4
  } from "../../plugins/adapters/index.js";
5
- import {
6
- AssetsMap,
7
- MAX_UINT256
8
- } from "../../sdk/index.js";
5
+ import { AssetsMap, MAX_UINT256 } from "../../sdk/index.js";
9
6
  import { applyRWAWrapUnwrap } from "./applyRWAWrapUnwrap.js";
10
7
  import {
11
8
  ERROR_ADAPTER_CALL_OUTSIDE_BRACKET,
@@ -14,17 +11,14 @@ import {
14
11
  ERROR_UNPREVIEWABLE_ADAPTER_CALL,
15
12
  ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP
16
13
  } from "./types.js";
17
- function makeInnerOperationsState() {
14
+ function makeReplayState(account) {
18
15
  return {
19
- balances: new AssetsMap(),
20
- debt: 0n,
21
- totalDebt: 0n,
16
+ account,
22
17
  collateralAdded: new AssetsMap(),
23
- collateralWithdrawn: new AssetsMap(),
24
- quotaChanges: []
18
+ collateralWithdrawn: new AssetsMap()
25
19
  };
26
20
  }
27
- async function applyInnerOperations(sdk, multicall, state) {
21
+ async function replayInnerOperations(sdk, multicall, state) {
28
22
  let inBracket = false;
29
23
  let error;
30
24
  for (const op of multicall) {
@@ -37,13 +31,13 @@ async function applyInnerOperations(sdk, multicall, state) {
37
31
  applyWithdrawCollateral(state, op);
38
32
  break;
39
33
  case "IncreaseBorrowedAmount":
40
- applyIncreaseDebt(state, op);
34
+ state.account.increaseDebt(op.amount);
41
35
  break;
42
36
  case "DecreaseBorrowedAmount":
43
- applyDecreaseDebt(state, op);
37
+ state.account.repay(op.amount);
44
38
  break;
45
39
  case "UpdateQuota":
46
- state.quotaChanges.push({ token: op.token, balance: op.change });
40
+ state.account.updateQuota(op.token, op.change);
47
41
  break;
48
42
  case "StoreExpectedBalances":
49
43
  if (inBracket) {
@@ -54,7 +48,7 @@ async function applyInnerOperations(sdk, multicall, state) {
54
48
  }
55
49
  inBracket = true;
56
50
  for (const { token, balance } of op.deltas) {
57
- state.balances.inc(token, balance);
51
+ state.account.balances.inc(token, balance);
58
52
  }
59
53
  break;
60
54
  case "CompareBalances":
@@ -67,7 +61,12 @@ async function applyInnerOperations(sdk, multicall, state) {
67
61
  inBracket = false;
68
62
  break;
69
63
  case "Execute":
70
- opError = await applyExecute(sdk, op, inBracket, state.balances);
64
+ opError = await applyExecute(
65
+ sdk,
66
+ op,
67
+ inBracket,
68
+ state.account.balances
69
+ );
71
70
  break;
72
71
  }
73
72
  error ??= opError;
@@ -82,27 +81,14 @@ async function applyInnerOperations(sdk, multicall, state) {
82
81
  }
83
82
  function applyAddCollateral(state, op) {
84
83
  state.collateralAdded.inc(op.token, op.amount);
85
- state.balances.inc(op.token, op.amount);
84
+ state.account.balances.inc(op.token, op.amount);
86
85
  }
87
86
  function applyWithdrawCollateral(state, op) {
88
- const running = state.balances.getOrZero(op.token);
87
+ const running = state.account.balances.getOrZero(op.token);
89
88
  const amount = op.amount === MAX_UINT256 ? running > 0n ? running : 0n : op.amount;
90
- state.balances.dec(op.token, amount);
89
+ state.account.balances.dec(op.token, amount);
91
90
  state.collateralWithdrawn.inc(op.token, amount);
92
91
  }
93
- function applyIncreaseDebt(state, op) {
94
- state.debt += op.amount;
95
- state.totalDebt += op.amount;
96
- state.balances.inc(op.token, op.amount);
97
- }
98
- function applyDecreaseDebt(state, op) {
99
- const repaid = op.amount > state.totalDebt ? state.totalDebt : op.amount;
100
- state.balances.dec(op.token, repaid);
101
- state.totalDebt -= repaid;
102
- if (state.debt > state.totalDebt) {
103
- state.debt = state.totalDebt;
104
- }
105
- }
106
92
  async function applyExecute(sdk, op, inBracket, balances) {
107
93
  const adapter = sdk.getContract(op.adapter);
108
94
  if (!inBracket) {
@@ -146,6 +132,6 @@ function isRWAShare(sdk, adapter) {
146
132
  return false;
147
133
  }
148
134
  export {
149
- applyInnerOperations,
150
- makeInnerOperationsState
135
+ makeReplayState,
136
+ replayInnerOperations
151
137
  };
@@ -0,0 +1,16 @@
1
+ import { CreditAccountState } from "./CreditAccountState.js";
2
+ import {
3
+ makeReplayState,
4
+ replayInnerOperations
5
+ } from "./replayInnerOperations.js";
6
+ async function replayMulticall(sdk, operation, options) {
7
+ const before = CreditAccountState.fromCreditAccountData(
8
+ options.creditAccount
9
+ );
10
+ const after = makeReplayState(before.clone());
11
+ const error = await replayInnerOperations(sdk, operation.multicall, after);
12
+ return { before, after, error };
13
+ }
14
+ export {
15
+ replayMulticall
16
+ };
@@ -5,6 +5,7 @@ const ERROR_UNPREVIEWABLE_ADAPTER_CALL = 1004;
5
5
  const ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP = 1005;
6
6
  const ERROR_INVALID_TRANSACTION_VALUE = 1006;
7
7
  const ERROR_UNPRICEABLE_TOKEN = 2001;
8
+ const PREVIEW_DUST = 10n;
8
9
  export {
9
10
  ERROR_ADAPTER_CALL_OUTSIDE_BRACKET,
10
11
  ERROR_INVALID_TRANSACTION_VALUE,
@@ -12,5 +13,6 @@ export {
12
13
  ERROR_NON_ADAPTER_CALL_IN_BRACKET,
13
14
  ERROR_UNPREVIEWABLE_ADAPTER_CALL,
14
15
  ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP,
15
- ERROR_UNPRICEABLE_TOKEN
16
+ ERROR_UNPRICEABLE_TOKEN,
17
+ PREVIEW_DUST
16
18
  };
@@ -0,0 +1,83 @@
1
+ import type { Address } from "viem";
2
+ import { AssetsMap, type CreditAccountData } from "../../sdk/index.js";
3
+ /**
4
+ * Constructor properties of {@link CreditAccountState}.
5
+ */
6
+ export interface CreditAccountStateProps {
7
+ creditAccount: Address;
8
+ creditManager: Address;
9
+ underlying: Address;
10
+ balances?: AssetsMap;
11
+ quotas?: AssetsMap;
12
+ debt?: bigint;
13
+ totalDebt?: bigint;
14
+ }
15
+ /**
16
+ * A snapshot of a credit account's economic state (balances, quotas, debt)
17
+ * as used by operation previews, together with the account's identity.
18
+ *
19
+ * Used both as the pre-state seed of a multicall replay and as the running
20
+ * post-state mutated by it; changes are derived by diffing two snapshots.
21
+ */
22
+ export declare class CreditAccountState {
23
+ creditAccount: Address;
24
+ creditManager: Address;
25
+ /**
26
+ * Credit manager underlying
27
+ */
28
+ underlying: Address;
29
+ /**
30
+ * Per-token balances
31
+ */
32
+ balances: AssetsMap;
33
+ /**
34
+ * Per-token quotas
35
+ */
36
+ quotas: AssetsMap;
37
+ /**
38
+ * Debt principal
39
+ */
40
+ debt: bigint;
41
+ /**
42
+ * Total debt: principal + accrued interest + accrued fees.
43
+ * `decreaseDebt` amounts operate on total debt (interest and fees are
44
+ * repaid before principal), so principal alone is not enough to resolve
45
+ * either the underlying balance decrement or the final principal.
46
+ */
47
+ totalDebt: bigint;
48
+ constructor(props: CreditAccountStateProps);
49
+ /**
50
+ * The account-opening seed: everything zero/empty. The account doesn't
51
+ * exist yet at preview time, so `creditAccount` is the zero address;
52
+ * opening previews take identity from the parsed operation instead.
53
+ */
54
+ static beforeOpen(creditManager: Address, underlying: Address): CreditAccountState;
55
+ /**
56
+ * Pre-state of an existing account from its on-chain data, with dust
57
+ * balances and quotas (≤ 1 wei) filtered out.
58
+ */
59
+ static fromCreditAccountData(ca: CreditAccountData): CreditAccountState;
60
+ clone(): CreditAccountState;
61
+ /**
62
+ * Borrows `amount` of underlying: debt, total debt and the underlying
63
+ * balance all increase by it.
64
+ */
65
+ increaseDebt(amount: bigint): void;
66
+ /**
67
+ * Repays up to `amount` of underlying against the debt, clamped to the
68
+ * total debt (the facade never repays more than is owed). Interest and
69
+ * fees are repaid before principal (CreditLogic.calcDecrease), so
70
+ * principal only decreases once total debt drops below it. The underlying
71
+ * balance decreases by the repaid amount.
72
+ *
73
+ * @returns The actually repaid (post-clamp) amount.
74
+ */
75
+ repay(amount: bigint): bigint;
76
+ /**
77
+ * Applies a relative `updateQuota` change to the token's quota:
78
+ * `MIN_INT96` is the facade "disable quota" sentinel and zeroes it, other
79
+ * changes are added with the result clamped at zero (quotas cannot go
80
+ * negative on-chain).
81
+ */
82
+ updateQuota(token: Address, change: bigint): void;
83
+ }
@@ -0,0 +1,41 @@
1
+ import { type Address } from "viem";
2
+ import type { CreditAccountState } from "./CreditAccountState.js";
3
+ import type { DetectedDelayedOperation } from "./detectDelayedOperation.js";
4
+ import { type InstantOperationPreview } from "./types.js";
5
+ /**
6
+ * Oracle conversion, injected so unit tests don't need a market
7
+ */
8
+ export type ConvertFn = (token: Address, to: Address, amount: bigint) => bigint;
9
+ /**
10
+ * Builds the best-effort preview of the account state after the detected
11
+ * delayed withdrawal is claimed and its intent (if any) is resumed.
12
+ *
13
+ * Pure function: reads the post-instant account state, never mutates it and
14
+ * performs no network access. Swaps that the resume flow would route through
15
+ * the router are estimated with the injected oracle conversion; tokens the
16
+ * oracle cannot price contribute nothing and set a non-fatal
17
+ * `ERROR_UNPRICEABLE_TOKEN` error on the preview.
18
+ *
19
+ * Common claim step (all intents): the phantom token is burned (balance and
20
+ * quota zeroed) and the claim token is credited with the same amount 1:1.
21
+ *
22
+ * Intent-specific resume:
23
+ * - `CLOSE_ACCOUNT`: everything is swapped into the underlying, the debt is
24
+ * fully repaid and the rest is withdrawn to the user.
25
+ * - `DECREASE_LEVERAGE`: the claimed amount is swapped into the underlying
26
+ * and used to decrease the debt.
27
+ * - `WITHDRAW_COLLATERAL`: the recorded amount of the recorded token is
28
+ * withdrawn to the user, the rest of the claimed amount decreases the debt.
29
+ * - other intents and `intent: undefined`: claim-only, the post-claim swap
30
+ * target is not recoverable from the intent.
31
+ *
32
+ * The changes (`debtChange`, `quotasChange`, `assetsChange`) are reported
33
+ * relative to the account state before the whole transaction, not the
34
+ * post-instant state: to the user the delayed preview answers "where will
35
+ * the account end up compared to now", so the transient phantom token
36
+ * (minted by the instant part, burned by the claim) nets out to nothing.
37
+ *
38
+ * @param state - Account state after the instant part of the transaction.
39
+ * @param before - Account state before the transaction (the diff base).
40
+ */
41
+ export declare function buildDelayedPreview(state: CreditAccountState, before: CreditAccountState, detected: DetectedDelayedOperation, convert: ConvertFn): InstantOperationPreview;
@@ -0,0 +1,29 @@
1
+ import { type DelayedWithdrawalRequest, type SdkWithAdapters } from "../../plugins/adapters/index.js";
2
+ import { type DelayedIntent, type PluginsMap } from "../../sdk/index.js";
3
+ import type { InnerOperation } from "../parse/index.js";
4
+ /**
5
+ * A delayed-withdrawal request detected in a credit-facade multicall,
6
+ * produced by `detectDelayedOperation`.
7
+ */
8
+ export interface DetectedDelayedOperation {
9
+ /**
10
+ * Phantom/claim tokens from the adapter's `parseDelayedWithdrawalRequest`
11
+ */
12
+ request: DelayedWithdrawalRequest;
13
+ /**
14
+ * Decoded delayed intent; undefined when the request carries none, in
15
+ * which case the delayed preview is claim-only
16
+ */
17
+ intent?: DelayedIntent;
18
+ }
19
+ /**
20
+ * Scans a credit-facade multicall for a delayed-withdrawal request.
21
+ *
22
+ * @param sdk - SDK with the adapters plugin attached.
23
+ * @param multicall - Parsed inner operations of the multicall.
24
+ * @returns The detected request, or `undefined` when
25
+ * the multicall contains no delayed-withdrawal request.
26
+ * @throws InvalidDelayedIntentError when a request carries non-empty
27
+ * `extraData` that cannot be decoded as a `DelayedIntent`.
28
+ */
29
+ export declare function detectDelayedOperation<P extends PluginsMap>(sdk: SdkWithAdapters<P>, multicall: InnerOperation[]): DetectedDelayedOperation | undefined;
@@ -1,3 +1,4 @@
1
+ import type { Address, Hex } from "viem";
1
2
  /**
2
3
  * Thrown by `previewOperation` for parsed operations it cannot preview yet.
3
4
  * Currently only pool operations and credit account opening are supported.
@@ -7,3 +8,17 @@ export declare class UnsupportedOperationError extends Error {
7
8
  readonly operation: string;
8
9
  constructor(operation: string);
9
10
  }
11
+ /**
12
+ * Thrown when a delayed-withdrawal request carries non-empty `extraData`
13
+ * that cannot be decoded as a `DelayedIntent`. Requests produced by our
14
+ * stack always encode a valid intent, so garbage here means a
15
+ * malformed/foreign transaction that must not be previewed as if it were
16
+ * fine.
17
+ */
18
+ export declare class InvalidDelayedIntentError extends Error {
19
+ /** Adapter the withdrawal request was addressed to. */
20
+ readonly adapter: Address;
21
+ /** Raw `extraData` that failed to decode. */
22
+ readonly extraData: Hex;
23
+ constructor(adapter: Address, extraData: Hex, cause?: unknown);
24
+ }
@@ -1,8 +1,11 @@
1
- export * from "./applyInnerOperations.js";
2
- export * from "./applyQuotaChanges.js";
1
+ export * from "./buildDelayedPreview.js";
2
+ export * from "./CreditAccountState.js";
3
3
  export * from "./detectCloseOrRepay.js";
4
+ export * from "./detectDelayedOperation.js";
4
5
  export * from "./errors.js";
5
6
  export * from "./previewAdjustCreditAccount.js";
6
7
  export * from "./previewCloseOrRepayCreditAccount.js";
7
8
  export * from "./previewOperation.js";
9
+ export * from "./replayInnerOperations.js";
10
+ export * from "./replayMulticall.js";
8
11
  export * from "./types.js";
@@ -4,9 +4,9 @@ import type { PreviewOperationInput, PreviewOperationOptions } from "../types.js
4
4
  import { type AdjustCreditAccountPreview } from "./types.js";
5
5
  /**
6
6
  * Previews a `multicall`/`botMulticall` operation on an existing credit
7
- * account: fetches the account's pre-state (unless provided via options),
8
- * threads the multicall through {@link applyInnerOperations} and reports the
7
+ * account: threads the multicall through {@link replayMulticall} over the
8
+ * pre-resolved account state (`options.creditAccount`) and reports the
9
9
  * minimal guaranteed post-state alongside the changes relative to the
10
10
  * pre-state.
11
11
  */
12
- export declare function previewAdjustCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: MulticallOperation | RWAMulticallOperation, options?: PreviewOperationOptions): Promise<AdjustCreditAccountPreview>;
12
+ export declare function previewAdjustCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: MulticallOperation | RWAMulticallOperation, options: PreviewOperationOptions<true>): Promise<AdjustCreditAccountPreview>;
@@ -1,11 +1,11 @@
1
1
  import { type PluginsMap } from "../../sdk/index.js";
2
2
  import type { CloseCreditAccountOperation, MulticallOperation, RWAMulticallOperation } from "../parse/index.js";
3
3
  import type { PreviewOperationInput, PreviewOperationOptions } from "../types.js";
4
- import type { OperationPreview } from "./types.js";
4
+ import type { CloseCreditAccountPreview, RepayCreditAccountPreview } from "./types.js";
5
5
  /**
6
6
  * Any parsed operation that fully closes or repays a credit account: the
7
7
  * facade `closeCreditAccount` entry point (permanent closure) or a plain
8
8
  * multicall detected by `isCloseOrRepay` (zero-debt closure/repay).
9
9
  */
10
10
  export type CloseOrRepayOperation = CloseCreditAccountOperation | MulticallOperation | RWAMulticallOperation;
11
- export declare function previewCloseOrRepayCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: CloseOrRepayOperation, permanent: boolean, options?: PreviewOperationOptions): Promise<OperationPreview>;
11
+ export declare function previewCloseOrRepayCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: CloseOrRepayOperation, permanent: boolean, options: PreviewOperationOptions<true>): Promise<CloseCreditAccountPreview | RepayCreditAccountPreview>;
@@ -0,0 +1,44 @@
1
+ import { type SdkWithAdapters } from "../../plugins/adapters/index.js";
2
+ import { AssetsMap, type PluginsMap } from "../../sdk/index.js";
3
+ import type { InnerOperation } from "../parse/index.js";
4
+ import type { CreditAccountState } from "./CreditAccountState.js";
5
+ import { type OperationPreviewError } from "./types.js";
6
+ /**
7
+ * Running state threaded through a credit-facade multicall by
8
+ * {@link replayInnerOperations}: the account's post-state being mutated in
9
+ * facade execution order, plus per-multicall bookkeeping that is not account
10
+ * state (what was added from / withdrawn to the wallet).
11
+ */
12
+ export interface ReplayState {
13
+ /**
14
+ * Running account state, mutated in facade execution order. Seeded by the
15
+ * caller: `CreditAccountState.beforeOpen` for account opening, a clone of
16
+ * `CreditAccountState.fromCreditAccountData` for an existing account.
17
+ */
18
+ account: CreditAccountState;
19
+ /**
20
+ * Cumulative amounts added via `addCollateral`.
21
+ */
22
+ collateralAdded: AssetsMap;
23
+ /**
24
+ * Cumulative amounts withdrawn via `withdrawCollateral`, with `MAX_UINT256`
25
+ * resolved against the running balance at the point of the call.
26
+ */
27
+ collateralWithdrawn: AssetsMap;
28
+ }
29
+ /**
30
+ * Creates a {@link ReplayState} around the given account seed, with empty
31
+ * bookkeeping.
32
+ */
33
+ export declare function makeReplayState(account: CreditAccountState): ReplayState;
34
+ /**
35
+ * Replays a credit-facade multicall over `state`, mutating it in place in
36
+ * facade execution order. The result is the *minimal guaranteed* post-state.
37
+ *
38
+ * The function assumes that the call was generated by our frontend using
39
+ * router/withdrawal compressor, otherwise it returns an error, but still
40
+ * proceeds best-effort.
41
+ *
42
+ * @returns `undefined` on success, the error on a malformed multicall.
43
+ */
44
+ export declare function replayInnerOperations<P extends PluginsMap>(sdk: SdkWithAdapters<P>, multicall: InnerOperation[], state: ReplayState): Promise<OperationPreviewError | undefined>;