@gearbox-protocol/sdk 16.0.0-next.15 → 16.0.0-next.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/cjs/onchain/accounts/intents/open-strategy.js +12 -3
  2. package/dist/cjs/onchain/accounts/intents/realize.js +11 -0
  3. package/dist/cjs/onchain/accounts/intents/testing/market.js +1 -0
  4. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +6 -4
  5. package/dist/cjs/onchain/accounts/intents/tests/deposit.fixtures.js +5 -2
  6. package/dist/cjs/onchain/accounts/intents/utils/index.js +4 -0
  7. package/dist/cjs/onchain/accounts/intents/utils/price-impact.js +99 -0
  8. package/dist/cjs/onchain/accounts/intents/utils/router-path.js +98 -40
  9. package/dist/esm/onchain/accounts/intents/open-strategy.js +12 -3
  10. package/dist/esm/onchain/accounts/intents/realize.js +11 -0
  11. package/dist/esm/onchain/accounts/intents/testing/market.js +1 -0
  12. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +6 -4
  13. package/dist/esm/onchain/accounts/intents/tests/deposit.fixtures.js +5 -2
  14. package/dist/esm/onchain/accounts/intents/utils/index.js +2 -1
  15. package/dist/esm/onchain/accounts/intents/utils/price-impact.js +96 -0
  16. package/dist/esm/onchain/accounts/intents/utils/router-path.js +98 -40
  17. package/dist/types/onchain/accounts/index.d.ts +4 -4
  18. package/dist/types/onchain/accounts/intents/index.d.ts +4 -4
  19. package/dist/types/onchain/accounts/intents/open-strategy.d.ts +3 -0
  20. package/dist/types/onchain/accounts/intents/realize.d.ts +1 -1
  21. package/dist/types/onchain/accounts/intents/tail.d.ts +1 -1
  22. package/dist/types/onchain/accounts/intents/testing/expect.d.ts +1 -1
  23. package/dist/types/onchain/accounts/intents/testing/market.d.ts +2 -0
  24. package/dist/types/onchain/accounts/intents/testing/sdk-mock.d.ts +7 -0
  25. package/dist/types/onchain/accounts/intents/tests/deposit.fixtures.d.ts +1 -1
  26. package/dist/types/onchain/accounts/intents/types.d.ts +18 -2
  27. package/dist/types/onchain/accounts/intents/utils/index.d.ts +2 -1
  28. package/dist/types/onchain/accounts/intents/utils/price-impact.d.ts +49 -0
  29. package/dist/types/onchain/accounts/intents/utils/router-path.d.ts +9 -0
  30. package/dist/types/onchain/index.d.ts +4 -4
  31. package/dist/types/sdk/index.d.ts +2 -2
  32. package/dist/types/sdk/prepare/index.d.ts +2 -2
  33. package/dist/types/sdk/prepare/types.d.ts +4 -4
  34. package/package.json +1 -1
@@ -0,0 +1,96 @@
1
+ import { PERCENTAGE_FACTOR_1KK, PRICE_DECIMALS, WAD } from "../../../constants/math.js";
2
+ //#region src/onchain/accounts/intents/utils/price-impact.ts
3
+ /** `b1 = b0 / V0`: a dollar of the basket, the reference implementation's anchor. */
4
+ const PROBE_UNIT_USD_WAD = WAD;
5
+ /**
6
+ * `V0 = Σ b0ᵢ·pᵢ`, then `b1 = b0 / V0`, proportions kept.
7
+ *
8
+ * Refuses only what the reference refuses — a basket worth nothing, or one that
9
+ * rounds away entirely. Stricter guards here would report nothing where the old
10
+ * client reported a number.
11
+ */
12
+ function probeBasket(balances, oracle) {
13
+ if (balances.length === 0) return;
14
+ let basketWad = 0n;
15
+ for (const asset of balances) {
16
+ if (asset.balance <= 0n) continue;
17
+ const usd = oracle.safeConvertToUSD(asset.token, asset.balance);
18
+ if (usd !== null && usd > 0n) basketWad += usd * WAD / PRICE_DECIMALS;
19
+ }
20
+ if (basketWad <= 0n) return;
21
+ const probeWad = PROBE_UNIT_USD_WAD;
22
+ const scaled = balances.map((asset) => ({
23
+ token: asset.token,
24
+ balance: asset.balance * probeWad / basketWad
25
+ }));
26
+ if (!scaled.some((a) => a.balance > 0n)) return;
27
+ return {
28
+ balances: scaled,
29
+ basketWad,
30
+ probeWad
31
+ };
32
+ }
33
+ /** Fires the marginal-price quote for one leg; `undefined` if it cannot be measured. */
34
+ function startProbe(args) {
35
+ const basket = probeBasket(args.basket, args.oracle);
36
+ if (!basket) return;
37
+ return {
38
+ tokenOut: args.tokenOut,
39
+ basketWad: basket.basketWad,
40
+ probeWad: basket.probeWad,
41
+ probe: args.route(basket.balances).catch(() => void 0)
42
+ };
43
+ }
44
+ /** `convert` answers `0` for a negative amount, so convert the magnitude and re-sign. */
45
+ function toUnderlyingSigned(convert, token, amount) {
46
+ if (amount === 0n) return 0n;
47
+ const converted = convert(token, amount < 0n ? -amount : amount);
48
+ if (converted <= 0n) return;
49
+ return amount < 0n ? -converted : converted;
50
+ }
51
+ /**
52
+ * In `PERCENTAGE_FACTOR_1KK` (1_000_000 = 100%), negative for a loss. A base
53
+ * that is not positive falls back to the routed output.
54
+ */
55
+ function lossRate(args) {
56
+ const { lossUnd, expectedUnd, totalValue, netValue } = args;
57
+ const against = (base) => -(PERCENTAGE_FACTOR_1KK * lossUnd / (base > 0n ? base : expectedUnd));
58
+ return {
59
+ pathPriceImpact: against(expectedUnd),
60
+ netValuePriceImpact: against(netValue),
61
+ totalValuePriceImpact: against(totalValue)
62
+ };
63
+ }
64
+ /**
65
+ * Folds every leg into one rate, in the underlying — the unit its bases are in.
66
+ *
67
+ * All or nothing: a partial sum would understate the loss and draw a better
68
+ * price than the route offers.
69
+ */
70
+ async function collectPriceImpact(probes, ctx) {
71
+ if (probes.length === 0) return;
72
+ const quotes = await Promise.all(probes.map((leg) => leg.probe));
73
+ let expectedUnd = 0n;
74
+ let lossUnd = 0n;
75
+ for (const [index, leg] of probes.entries()) {
76
+ const unit = quotes[index];
77
+ if (unit === void 0 || unit <= 0n) return;
78
+ const expected = unit * leg.basketWad / leg.probeWad;
79
+ if (expected <= 0n) return;
80
+ const expectedInUnd = ctx.toUnderlying(leg.tokenOut, expected);
81
+ if (expectedInUnd <= 0n) return;
82
+ const loss = toUnderlyingSigned(ctx.toUnderlying, leg.tokenOut, expected - leg.realAmount);
83
+ if (loss === void 0) return;
84
+ expectedUnd += expectedInUnd;
85
+ lossUnd += loss;
86
+ }
87
+ if (expectedUnd <= 0n) return;
88
+ return lossRate({
89
+ lossUnd,
90
+ expectedUnd,
91
+ totalValue: ctx.totalValue,
92
+ netValue: ctx.netValue
93
+ });
94
+ }
95
+ //#endregion
96
+ export { collectPriceImpact, lossRate, startProbe };
@@ -1,5 +1,6 @@
1
1
  import { toRouterCaSlice } from "./common.js";
2
2
  import { convertAmount } from "./convert-amount.js";
3
+ import { startProbe } from "./price-impact.js";
3
4
  //#region src/onchain/accounts/intents/utils/router-path.ts
4
5
  /**
5
6
  * The engine's only door to the pathfinder.
@@ -17,68 +18,124 @@ function createRouterPaths(args) {
17
18
  collateralTokens: suite.creditManager.collateralTokens.map((t) => t.toLowerCase())
18
19
  };
19
20
  const router = sdk.routerFor({ creditFacade: suite.creditFacade.address });
21
+ const { priceOracle } = sdk.marketRegister.findByCreditManager(creditAccount.creditManager);
22
+ const quoteSwap = (input) => {
23
+ const spending = [{
24
+ token: input.tokenIn,
25
+ balance: input.amount + input.keep
26
+ }];
27
+ return input.keep > 0n ? router.findManyToOnePath({
28
+ creditAccount: toRouterCaSlice(creditAccount, spending),
29
+ creditManager: cmSlice,
30
+ expectedBalances: spending,
31
+ leftoverBalances: [{
32
+ token: input.tokenIn,
33
+ balance: input.keep
34
+ }],
35
+ target: input.tokenOut,
36
+ slippage
37
+ }) : router.findOneTokenPath({
38
+ creditAccount: toRouterCaSlice(creditAccount, spending),
39
+ creditManager: cmSlice,
40
+ tokenIn: input.tokenIn,
41
+ tokenOut: input.tokenOut,
42
+ amount: input.amount,
43
+ slippage
44
+ });
45
+ };
46
+ const quoteClose = (balances) => router.findBestClosePath({
47
+ creditAccount: toRouterCaSlice(creditAccount, balances),
48
+ creditManager: cmSlice,
49
+ balances: {
50
+ expectedBalances: balances,
51
+ leftoverBalances: [],
52
+ tokensToClaim: []
53
+ },
54
+ slippage
55
+ });
56
+ const quoteOpen = (expectedBalances, leftoverBalances, target) => router.findOpenStrategyPath({
57
+ creditManager: cmSlice,
58
+ expectedBalances,
59
+ leftoverBalances,
60
+ target,
61
+ slippage
62
+ });
20
63
  return {
21
64
  async swap({ tokenIn, tokenOut, amount, keep = 0n }) {
22
65
  if (amount <= 0n) return {
23
66
  amount: 0n,
24
67
  minAmount: 0n,
25
- calls: []
68
+ calls: [],
69
+ probe: void 0
26
70
  };
27
71
  if (keep < 0n) throw new Error(`swap: spending ${amount} of ${tokenIn} exceeds its balance`);
28
- if (keep > 0n) {
29
- const expectedBalances = [{
30
- token: tokenIn,
31
- balance: amount + keep
32
- }];
33
- return router.findManyToOnePath({
34
- creditAccount: toRouterCaSlice(creditAccount, expectedBalances),
35
- creditManager: cmSlice,
36
- expectedBalances,
37
- leftoverBalances: [{
38
- token: tokenIn,
39
- balance: keep
40
- }],
41
- target: tokenOut,
42
- slippage
43
- });
44
- }
45
- return router.findOneTokenPath({
46
- creditAccount: toRouterCaSlice(creditAccount, [{
72
+ const probe = startProbe({
73
+ basket: [{
47
74
  token: tokenIn,
48
75
  balance: amount
49
- }]),
50
- creditManager: cmSlice,
76
+ }],
77
+ tokenOut,
78
+ oracle: priceOracle,
79
+ route: async ([only]) => {
80
+ if (!only) return 0n;
81
+ return (await quoteSwap({
82
+ tokenIn: only.token,
83
+ tokenOut,
84
+ amount: only.balance,
85
+ keep: 0n
86
+ })).amount;
87
+ }
88
+ });
89
+ const leg = await quoteSwap({
51
90
  tokenIn,
52
91
  tokenOut,
53
92
  amount,
54
- slippage
93
+ keep
55
94
  });
95
+ return {
96
+ ...leg,
97
+ probe: probe && {
98
+ ...probe,
99
+ realAmount: leg.amount
100
+ }
101
+ };
56
102
  },
57
103
  async closeAll({ balances }) {
58
- const { amount, minAmount, calls } = await router.findBestClosePath({
59
- creditAccount: toRouterCaSlice(creditAccount, balances),
60
- creditManager: cmSlice,
61
- balances: {
62
- expectedBalances: balances,
63
- leftoverBalances: [],
64
- tokensToClaim: []
65
- },
66
- slippage
104
+ const probe = startProbe({
105
+ basket: balances,
106
+ tokenOut: creditAccount.underlying,
107
+ oracle: priceOracle,
108
+ route: async (quoted) => (await quoteClose(quoted)).amount
67
109
  });
68
- return {
110
+ const { amount, minAmount, calls } = await quoteClose(balances);
111
+ const leg = {
69
112
  amount,
70
113
  minAmount,
71
114
  calls: [...calls]
72
115
  };
116
+ return {
117
+ ...leg,
118
+ probe: probe && {
119
+ ...probe,
120
+ realAmount: leg.amount
121
+ }
122
+ };
73
123
  },
74
124
  async openStrategy({ expectedBalances, leftoverBalances, target }) {
75
- return router.findOpenStrategyPath({
76
- creditManager: cmSlice,
77
- expectedBalances,
78
- leftoverBalances,
79
- target,
80
- slippage
125
+ const probe = startProbe({
126
+ basket: expectedBalances,
127
+ tokenOut: target,
128
+ oracle: priceOracle,
129
+ route: async (balances) => (await quoteOpen(balances, [], target)).amount
81
130
  });
131
+ const leg = await quoteOpen(expectedBalances, leftoverBalances, target);
132
+ return {
133
+ ...leg,
134
+ probe: probe && {
135
+ ...probe,
136
+ realAmount: leg.amount
137
+ }
138
+ };
82
139
  }
83
140
  };
84
141
  }
@@ -98,7 +155,8 @@ function createOraclePaths(args) {
98
155
  const estimate = (amount) => ({
99
156
  amount,
100
157
  minAmount: amount,
101
- calls: []
158
+ calls: [],
159
+ probe: void 0
102
160
  });
103
161
  return {
104
162
  async swap({ tokenIn, tokenOut, amount }) {
@@ -21,10 +21,10 @@ import { PeripheryCompressorV310Contract } from "./bots/PeripheryCompressorV310C
21
21
  import "./bots/index.js";
22
22
  import { CreditAccountsServiceV310 } from "./CreditAccountsServiceV310.js";
23
23
  import { LeverageBand } from "./intents/leverage-band.js";
24
- import { OpenStrategyPreview, OpenStrategyProps } from "./intents/open-strategy.js";
25
- import { IntentPreviewError, PreviewErrorDetails, PreviewErrorReason, PreviewRefusal, refuse } from "./intents/refusal.js";
26
- import { AddCollateralIntent, AdjustLeverageIntent, CreditAccountSlice, DelayableIntent, DelayedRoute, DelayedStart, DelayedStartResult, DepositStrategyIntent, FinishIntentProps, InstantRoute, IntentPreviewResult, IntentRoutesResult, OperationState, RepayStrategyIntent, ResumableIntent, RouteRefusals, StartIntent, WithdrawAssetIntent, WithdrawStrategyIntent } from "./intents/types.js";
27
24
  import { AccountCalculatorOperation } from "./intents/operations.js";
25
+ import { IntentPreviewError, PreviewErrorDetails, PreviewErrorReason, PreviewRefusal, refuse } from "./intents/refusal.js";
26
+ import { AddCollateralIntent, AdjustLeverageIntent, CreditAccountSlice, DelayableIntent, DelayedRoute, DelayedStart, DelayedStartResult, DepositStrategyIntent, FinishIntentProps, InstantRoute, IntentPreviewResult, IntentRoutesResult, OperationState, PathLossRate, RepayStrategyIntent, ResumableIntent, RouteRefusals, StartIntent, WithdrawAssetIntent, WithdrawStrategyIntent } from "./intents/types.js";
27
+ import { OpenStrategyPreview, OpenStrategyProps } from "./intents/open-strategy.js";
28
28
  import { fetchCreditAccountSlice, toCreditAccountSlice } from "./intents/utils/credit-account-slice.js";
29
29
  import { CreditAccountOperationsService, OpenStrategyPreviewResult } from "./intents/index.js";
30
30
  import { LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./liquidations/constants.js";
@@ -32,4 +32,4 @@ import { BuildLiquidationTxProps, BuildLiquidationTxPropsBase, GetLiquidatableAc
32
32
  import { LiquidationsService } from "./liquidations/LiquidationsService.js";
33
33
  import { MultichainLiquidationsService } from "./liquidations/MultichainLiquidationsService.js";
34
34
  import "./liquidations/index.js";
35
- export { AbstractWithdrawalCompressorContract, AccountBotsService, type AccountCalculatorOperation, AccountToCheck, type AddCollateralIntent, type AdjustLeverageIntent, AssembleCaOperationsProps, AssembleClaimDelayedCallsProps, AssembleCloseCreditAccountCallsProps, AssembleRepayCreditAccountCallsProps, AssembleStartDelayedWithdrawalCallsProps, BotStatusCall, BotsDirectResponse, BuildLiquidationTxProps, BuildLiquidationTxPropsBase, CMSlice, ClaimFarmRewardsProps, ClaimableWithdrawal, CloseCreditAccountResult, ConnectedBotsCall, ConnectedBotsPerAccount, CreditAccountCompressor, CreditAccountCompressorV310Contract, CreditAccountDataCall, CreditAccountFilter, CreditAccountOperationResult, CreditAccountOperationsService, CreditAccountReadOptions, type CreditAccountSlice, CreditAccountsCall, CreditAccountsQuery, CreditAccountsReadOptions, CreditAccountsServiceV310, CreditAccountsTarget, CreditManagerFilter, CreditManagerOperationResult, CurrentWithdrawals, DELAYED_INTENT_TYPES, DELAYED_INTENT_VERSION, type DelayableIntent, DelayedIntentExtended, type DelayedRoute, type DelayedStart, type DelayedStartResult, type DepositStrategyIntent, EncodableCreditAccountOperation, type FinishIntentProps, FullyLiquidateProps, FullyLiquidateResult, GetApprovalAddressProps, GetConnectedBotsResponse, GetConnectedBotsResult, GetConnectedMigrationBotsResult, GetCreditAccountsArgs, GetCreditAccountsOptions, GetExternalAccountCurrentWithdrawalsProps, GetLiquidatableAccountsProps, GetLiquidationDetailsProps, GetLiquidationDetailsPropsBase, GetLiquidationPositionsProps, GetLiquidationPositionsPropsBase, GetPendingWithdrawalsProps, GetPendingWithdrawalsResult, GetWithdrawalRequestResultProps, ICreditAccountsService, IRedemptionLoggerContract, IWithdrawalCompressorContract, type InstantRoute, IntentPreviewError, type IntentPreviewResult, type IntentRoutesResult, InvalidDelayedIntentError, LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS, type LeverageBand, LiquidationsService, LoadRWALiquidatorsProps, MulticallWithFailure, MultichainLiquidationsService, OnchainLiquidationCall, OnchainLiquidationData, OnchainLiquidationOutput, OnchainRequestableWithdrawal, OpenCAProps, type OpenStrategyPreview, OpenStrategyPreviewResult, type OpenStrategyProps, type OperationState, PartiallyLiquidateProps, PendingWithdrawal, PeripheryCompressorV310Contract, PreviewDelayedWithdrawalProps, type PreviewErrorDetails, type PreviewErrorReason, type PreviewRefusal, RWALiquidatorInfo, RedemptionLog, RedemptionLoggerV310Contract, type RepayStrategyIntent, RequestableWithdrawal, type ResumableIntent, Rewards, type RouteRefusals, SetBotProps, SetBotResult, type StartIntent, type WithdrawAssetIntent, type WithdrawStrategyIntent, WithdrawableAsset, WithdrawalCompressorLocation, WithdrawalCompressorV310Contract, WithdrawalCompressorV311Contract, WithdrawalCompressorV313Contract, WithdrawalCompressorVersion, WithdrawalOutput, WithdrawalStatus, WithdrawalsState, createRedemptionLogger, createWithdrawalCompressor, decodeDelayedIntent, encodeDelayedIntent, fetchCreditAccountSlice, getWithdrawalCompressorAddress, iCreditAccountAbi, refuse, toClaimableWithdrawal, toCreditAccountSlice, toPendingWithdrawal, toRequestableWithdrawal, toWithdrawalStatus };
35
+ export { AbstractWithdrawalCompressorContract, AccountBotsService, type AccountCalculatorOperation, AccountToCheck, type AddCollateralIntent, type AdjustLeverageIntent, AssembleCaOperationsProps, AssembleClaimDelayedCallsProps, AssembleCloseCreditAccountCallsProps, AssembleRepayCreditAccountCallsProps, AssembleStartDelayedWithdrawalCallsProps, BotStatusCall, BotsDirectResponse, BuildLiquidationTxProps, BuildLiquidationTxPropsBase, CMSlice, ClaimFarmRewardsProps, ClaimableWithdrawal, CloseCreditAccountResult, ConnectedBotsCall, ConnectedBotsPerAccount, CreditAccountCompressor, CreditAccountCompressorV310Contract, CreditAccountDataCall, CreditAccountFilter, CreditAccountOperationResult, CreditAccountOperationsService, CreditAccountReadOptions, type CreditAccountSlice, CreditAccountsCall, CreditAccountsQuery, CreditAccountsReadOptions, CreditAccountsServiceV310, CreditAccountsTarget, CreditManagerFilter, CreditManagerOperationResult, CurrentWithdrawals, DELAYED_INTENT_TYPES, DELAYED_INTENT_VERSION, type DelayableIntent, DelayedIntentExtended, type DelayedRoute, type DelayedStart, type DelayedStartResult, type DepositStrategyIntent, EncodableCreditAccountOperation, type FinishIntentProps, FullyLiquidateProps, FullyLiquidateResult, GetApprovalAddressProps, GetConnectedBotsResponse, GetConnectedBotsResult, GetConnectedMigrationBotsResult, GetCreditAccountsArgs, GetCreditAccountsOptions, GetExternalAccountCurrentWithdrawalsProps, GetLiquidatableAccountsProps, GetLiquidationDetailsProps, GetLiquidationDetailsPropsBase, GetLiquidationPositionsProps, GetLiquidationPositionsPropsBase, GetPendingWithdrawalsProps, GetPendingWithdrawalsResult, GetWithdrawalRequestResultProps, ICreditAccountsService, IRedemptionLoggerContract, IWithdrawalCompressorContract, type InstantRoute, IntentPreviewError, type IntentPreviewResult, type IntentRoutesResult, InvalidDelayedIntentError, LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS, type LeverageBand, LiquidationsService, LoadRWALiquidatorsProps, MulticallWithFailure, MultichainLiquidationsService, OnchainLiquidationCall, OnchainLiquidationData, OnchainLiquidationOutput, OnchainRequestableWithdrawal, OpenCAProps, type OpenStrategyPreview, OpenStrategyPreviewResult, type OpenStrategyProps, type OperationState, PartiallyLiquidateProps, type PathLossRate, PendingWithdrawal, PeripheryCompressorV310Contract, PreviewDelayedWithdrawalProps, type PreviewErrorDetails, type PreviewErrorReason, type PreviewRefusal, RWALiquidatorInfo, RedemptionLog, RedemptionLoggerV310Contract, type RepayStrategyIntent, RequestableWithdrawal, type ResumableIntent, Rewards, type RouteRefusals, SetBotProps, SetBotResult, type StartIntent, type WithdrawAssetIntent, type WithdrawStrategyIntent, WithdrawableAsset, WithdrawalCompressorLocation, WithdrawalCompressorV310Contract, WithdrawalCompressorV311Contract, WithdrawalCompressorV313Contract, WithdrawalCompressorVersion, WithdrawalOutput, WithdrawalStatus, WithdrawalsState, createRedemptionLogger, createWithdrawalCompressor, decodeDelayedIntent, encodeDelayedIntent, fetchCreditAccountSlice, getWithdrawalCompressorAddress, iCreditAccountAbi, refuse, toClaimableWithdrawal, toCreditAccountSlice, toPendingWithdrawal, toRequestableWithdrawal, toWithdrawalStatus };
@@ -1,9 +1,9 @@
1
1
  import { SDKConstruct } from "../../base/SDKConstruct.js";
2
2
  import { LeverageBand, LeverageBandProps } from "./leverage-band.js";
3
- import { OpenStrategyPreview, OpenStrategyProps } from "./open-strategy.js";
4
- import { IntentPreviewError, PreviewErrorDetails, PreviewErrorReason, PreviewRefusal, refuse } from "./refusal.js";
5
- import { AddCollateralIntent, AdjustLeverageIntent, CreditAccountSlice, DelayableIntent, DelayedRoute, DelayedStart, DelayedStartResult, DepositStrategyIntent, FinishIntentProps, InstantRoute, IntentPreviewResult, IntentRoutesResult, OperationState, RepayStrategyIntent, ResumableIntent, RouteRefusals, StartIntent, StartIntentProps, WithdrawAssetIntent, WithdrawStrategyIntent } from "./types.js";
6
3
  import { AccountCalculatorOperation } from "./operations.js";
4
+ import { IntentPreviewError, PreviewErrorDetails, PreviewErrorReason, PreviewRefusal, refuse } from "./refusal.js";
5
+ import { AddCollateralIntent, AdjustLeverageIntent, CreditAccountSlice, DelayableIntent, DelayedRoute, DelayedStart, DelayedStartResult, DepositStrategyIntent, FinishIntentProps, InstantRoute, IntentPreviewResult, IntentRoutesResult, OperationState, PathLossRate, RepayStrategyIntent, ResumableIntent, RouteRefusals, StartIntent, StartIntentProps, WithdrawAssetIntent, WithdrawStrategyIntent } from "./types.js";
6
+ import { OpenStrategyPreview, OpenStrategyProps } from "./open-strategy.js";
7
7
  import { fetchCreditAccountSlice, toCreditAccountSlice } from "./utils/credit-account-slice.js";
8
8
  import { Address } from "viem";
9
9
  //#region src/onchain/accounts/intents/index.d.ts
@@ -172,4 +172,4 @@ declare class CreditAccountOperationsService extends SDKConstruct {
172
172
  openStrategyIntent(props: OpenStrategyProps): Promise<OpenStrategyPreviewResult>;
173
173
  }
174
174
  //#endregion
175
- export { type AccountCalculatorOperation, type AddCollateralIntent, type AdjustLeverageIntent, CreditAccountOperationsService, type CreditAccountSlice, type DelayableIntent, type DelayedRoute, type DelayedStart, type DelayedStartResult, type DepositStrategyIntent, type FinishIntentProps, type InstantRoute, IntentPreviewError, type IntentPreviewResult, type IntentRoutesResult, type LeverageBand, type OpenStrategyPreview, OpenStrategyPreviewResult, type OpenStrategyProps, type OperationState, type PreviewErrorDetails, type PreviewErrorReason, type PreviewRefusal, type RepayStrategyIntent, type ResumableIntent, type RouteRefusals, type StartIntent, type WithdrawAssetIntent, type WithdrawStrategyIntent, fetchCreditAccountSlice, refuse, toCreditAccountSlice };
175
+ export { type AccountCalculatorOperation, type AddCollateralIntent, type AdjustLeverageIntent, CreditAccountOperationsService, type CreditAccountSlice, type DelayableIntent, type DelayedRoute, type DelayedStart, type DelayedStartResult, type DepositStrategyIntent, type FinishIntentProps, type InstantRoute, IntentPreviewError, type IntentPreviewResult, type IntentRoutesResult, type LeverageBand, type OpenStrategyPreview, OpenStrategyPreviewResult, type OpenStrategyProps, type OperationState, type PathLossRate, type PreviewErrorDetails, type PreviewErrorReason, type PreviewRefusal, type RepayStrategyIntent, type ResumableIntent, type RouteRefusals, type StartIntent, type WithdrawAssetIntent, type WithdrawStrategyIntent, fetchCreditAccountSlice, refuse, toCreditAccountSlice };
@@ -4,6 +4,7 @@ import "../../../model/index.js";
4
4
  import { Asset } from "../../base/types.js";
5
5
  import { MultiCall } from "../../types/transactions.js";
6
6
  import { OnchainSDK } from "../../OnchainSDK.js";
7
+ import { PathLossRate } from "./types.js";
7
8
  import "../../index.js";
8
9
  import { Address } from "viem";
9
10
  //#region src/onchain/accounts/intents/open-strategy.d.ts
@@ -60,6 +61,8 @@ interface OpenStrategyPreview {
60
61
  collateral: bigint;
61
62
  /** Position size — collateral plus debt, in underlying. */
62
63
  totalValue: bigint;
64
+ /** What the routed leg lost to market depth; `undefined` if not measured. */
65
+ priceImpact: PathLossRate | undefined;
63
66
  /** Expected post-open balances. */
64
67
  averageAssets: TokenAmount[];
65
68
  /** Floor post-open balances after slippage. */
@@ -1,7 +1,7 @@
1
1
  import { MultiCall } from "../../types/transactions.js";
2
2
  import { OnchainSDK } from "../../OnchainSDK.js";
3
- import { CreditAccountSlice, DelayedStart, OperationState } from "./types.js";
4
3
  import { AccountCalculatorOperation } from "./operations.js";
4
+ import { CreditAccountSlice, DelayedStart, OperationState } from "./types.js";
5
5
  import "../../index.js";
6
6
  import { Step } from "./plan.js";
7
7
  import { RouterPaths } from "./utils/router-path.js";
@@ -1,7 +1,7 @@
1
1
  import { ClaimableWithdrawal } from "../withdrawal-compressor/types.js";
2
2
  import { OnchainSDK } from "../../OnchainSDK.js";
3
- import { CreditAccountSlice, DelayedStart, OperationState, ResumableIntent } from "./types.js";
4
3
  import { AccountCalculatorOperation, StartDelayedWithdrawalOperation } from "./operations.js";
4
+ import { CreditAccountSlice, DelayedStart, OperationState, ResumableIntent } from "./types.js";
5
5
  import "../../index.js";
6
6
  import { AccountView, Step } from "./plan.js";
7
7
  //#region src/onchain/accounts/intents/tail.d.ts
@@ -1,8 +1,8 @@
1
1
  import { TokenAmount } from "../../../../model/primitives.js";
2
2
  import "../../../../model/index.js";
3
3
  import { MultiCall } from "../../../types/transactions.js";
4
- import { DelayedStartResult, IntentPreviewResult, OperationState } from "../types.js";
5
4
  import { AccountCalculatorOperation } from "../operations.js";
5
+ import { DelayedStartResult, IntentPreviewResult, OperationState } from "../types.js";
6
6
  import "../../../index.js";
7
7
  import { Address } from "viem";
8
8
  //#region src/onchain/accounts/intents/testing/expect.d.ts
@@ -72,6 +72,8 @@ interface MarketSdkExtras {
72
72
  maxDebtPerBlockMultiplier?: number;
73
73
  /** Tokens the facade forbids. */
74
74
  forbiddenTokens?: Address[];
75
+ /** What a routed swap returns; linear when omitted. */
76
+ routeQuote?: (amount: bigint) => bigint;
75
77
  }
76
78
  /** Mock SDK on the shared fixture market. */
77
79
  declare function buildMarketSdk(extras?: MarketSdkExtras): OnchainSDK;
@@ -114,6 +114,13 @@ interface BuildMockSdkArgs {
114
114
  * `accountDebt` lands as the principal with no interest or fees accrued.
115
115
  */
116
116
  creditAccounts?: CreditAccountSlice[];
117
+ /**
118
+ * What a routed swap returns for a given input, so a case can quote a market
119
+ * with depth. The default is linear — every route returns its input — which
120
+ * reports no price impact at all, since the probe scales down in exactly the
121
+ * same proportion.
122
+ */
123
+ routeQuote?: (amount: bigint) => bigint;
117
124
  }
118
125
  /** One redemption venue of the mock compressor. */
119
126
  interface MockDelayedVenue {
@@ -52,7 +52,7 @@ declare const NATIVE_VALUE = 1000000000000000000n;
52
52
  * the addCollateral op.
53
53
  */
54
54
  declare const case_native_coin: DepositCase;
55
- declare function buildDepositSdk(c: DepositCase): OnchainSDK;
55
+ declare function buildDepositSdk(c: DepositCase, routeQuote?: (amount: bigint) => bigint): OnchainSDK;
56
56
  declare function buildDepositProps(c: DepositCase, sdk: OnchainSDK): {
57
57
  intent: DepositStrategyIntent;
58
58
  creditAccount: CreditAccountSlice;
@@ -7,8 +7,8 @@ import { Asset } from "../../base/types.js";
7
7
  import { RouterCASlice } from "../../router/types.js";
8
8
  import { MultiCall } from "../../types/transactions.js";
9
9
  import { OnchainSDK } from "../../OnchainSDK.js";
10
- import { PreviewErrorReason, PreviewRefusal } from "./refusal.js";
11
10
  import { AccountCalculatorOperation } from "./operations.js";
11
+ import { PreviewErrorReason, PreviewRefusal } from "./refusal.js";
12
12
  import "../../index.js";
13
13
  import { Address } from "viem";
14
14
  //#region src/onchain/accounts/intents/types.d.ts
@@ -21,6 +21,17 @@ type CreditAccountSlice = Omit<RouterCASlice, "debt"> & {
21
21
  /** either base debt or debt plus interest and fees */
22
22
  accountDebt: bigint;
23
23
  };
24
+ /**
25
+ * Price impact against three bases: the routed output, net value, total value.
26
+ *
27
+ * In `PERCENTAGE_FACTOR_1KK` (1_000_000 = 100%), negative for a loss — the
28
+ * legacy 1e6 scale, not the `Bps` the rest of this module speaks.
29
+ */
30
+ interface PathLossRate {
31
+ pathPriceImpact: bigint;
32
+ netValuePriceImpact: bigint;
33
+ totalValuePriceImpact: bigint;
34
+ }
24
35
  /** Projected account metrics once the operations execute. */
25
36
  interface OperationState {
26
37
  /**
@@ -70,6 +81,11 @@ interface OperationState {
70
81
  * absent rather than present at zero.
71
82
  */
72
83
  quotas: Record<Address, Asset>;
84
+ /**
85
+ * What the routed legs lost to market depth. `undefined` where nothing was
86
+ * routed or nothing could be measured — never a manufactured zero.
87
+ */
88
+ priceImpact: PathLossRate | undefined;
73
89
  }
74
90
  /**
75
91
  * What a preview yields: the operation chain, the state it projects, and the
@@ -405,4 +421,4 @@ type FinishIntentProps = StartIntentProps & {
405
421
  claimable: ClaimableWithdrawal;
406
422
  };
407
423
  //#endregion
408
- export { AddCollateralIntent, AdjustLeverageIntent, CreditAccountSlice, DelayableIntent, DelayedRoute, DelayedStart, DelayedStartResult, DepositStrategyIntent, FinishIntentProps, InstantRoute, IntentPreviewResult, IntentRoutesResult, OperationState, RepayStrategyIntent, ResumableIntent, RouteRefusals, StartIntent, StartIntentProps, WithdrawAssetIntent, WithdrawStrategyIntent };
424
+ export { AddCollateralIntent, AdjustLeverageIntent, CreditAccountSlice, DelayableIntent, DelayedRoute, DelayedStart, DelayedStartResult, DepositStrategyIntent, FinishIntentProps, InstantRoute, IntentPreviewResult, IntentRoutesResult, OperationState, PathLossRate, RepayStrategyIntent, ResumableIntent, RouteRefusals, StartIntent, StartIntentProps, WithdrawAssetIntent, WithdrawStrategyIntent };
@@ -1,4 +1,5 @@
1
1
  import { fetchCreditAccountSlice, toCreditAccountSlice } from "./credit-account-slice.js";
2
+ import { LegProbe, collectPriceImpact, lossRate, startProbe } from "./price-impact.js";
2
3
  import { OpenStrategyLeg, RouterPaths, SwapLeg, createOraclePaths, createRouterPaths } from "./router-path.js";
3
4
  import { adjustStateToSnapshot } from "./adjust-state-to-snapshot.js";
4
5
  import { assembleOperationCalls } from "./assemble-operation-calls.js";
@@ -8,4 +9,4 @@ import { convertAmount } from "./convert-amount.js";
8
9
  import { ConvertFn, LedgerSnapshot, OperationLedger } from "./ledger.js";
9
10
  import { CandidateToken, isPhantomToken, isRedemptionPhantomToken, pickFattestNonPhantomToken, rankAccountTokens } from "./pick-token.js";
10
11
  import { clearedQuotas, getQuotasForUpdate, quotasAfterUpdate } from "./quotas-for-update.js";
11
- export { CandidateToken, ConvertFn, LedgerSnapshot, OpenStrategyLeg, OperationLedger, RouterPaths, SwapLeg, adjustStateToSnapshot, assembleOperationCalls, calcBorrowedAmountPlusInterestAndFees, clearedQuotas, convertAmount, createOraclePaths, createRouterPaths, eq, fetchCreditAccountSlice, getQuotasForUpdate, isPhantomToken, isRedemptionPhantomToken, pickFattestNonPhantomToken, quotasAfterUpdate, rankAccountTokens, toCreditAccountSlice, toRouterCaSlice, toTargetDecimals };
12
+ export { CandidateToken, ConvertFn, LedgerSnapshot, LegProbe, OpenStrategyLeg, OperationLedger, RouterPaths, SwapLeg, adjustStateToSnapshot, assembleOperationCalls, calcBorrowedAmountPlusInterestAndFees, clearedQuotas, collectPriceImpact, convertAmount, createOraclePaths, createRouterPaths, eq, fetchCreditAccountSlice, getQuotasForUpdate, isPhantomToken, isRedemptionPhantomToken, lossRate, pickFattestNonPhantomToken, quotasAfterUpdate, rankAccountTokens, startProbe, toCreditAccountSlice, toRouterCaSlice, toTargetDecimals };
@@ -0,0 +1,49 @@
1
+ import { Asset } from "../../../base/types.js";
2
+ import { IPriceOracleContract } from "../../../market/oracle/types.js";
3
+ import { PathLossRate } from "../types.js";
4
+ import "../../../index.js";
5
+ import { Address } from "viem";
6
+ //#region src/onchain/accounts/intents/utils/price-impact.d.ts
7
+ /** One leg's contribution to the preview's impact. */
8
+ interface LegProbe {
9
+ tokenOut: Address;
10
+ /**
11
+ * The real route's `amount`, never its `minAmount`: the floor is a tolerance
12
+ * the caller chose, not a cost the market charged.
13
+ */
14
+ realAmount: bigint;
15
+ basketWad: bigint;
16
+ probeWad: bigint;
17
+ /** Already in flight, and already neutralised — see {@link startProbe}. */
18
+ probe: Promise<bigint | undefined>;
19
+ }
20
+ /** Fires the marginal-price quote for one leg; `undefined` if it cannot be measured. */
21
+ declare function startProbe(args: {
22
+ basket: Asset[];
23
+ tokenOut: Address;
24
+ oracle: IPriceOracleContract;
25
+ route: (basket: Asset[]) => Promise<bigint | undefined>;
26
+ }): Omit<LegProbe, "realAmount"> | undefined;
27
+ /**
28
+ * In `PERCENTAGE_FACTOR_1KK` (1_000_000 = 100%), negative for a loss. A base
29
+ * that is not positive falls back to the routed output.
30
+ */
31
+ declare function lossRate(args: {
32
+ lossUnd: bigint;
33
+ expectedUnd: bigint;
34
+ totalValue: bigint;
35
+ netValue: bigint;
36
+ }): PathLossRate;
37
+ /**
38
+ * Folds every leg into one rate, in the underlying — the unit its bases are in.
39
+ *
40
+ * All or nothing: a partial sum would understate the loss and draw a better
41
+ * price than the route offers.
42
+ */
43
+ declare function collectPriceImpact(probes: LegProbe[], ctx: {
44
+ totalValue: bigint;
45
+ netValue: bigint;
46
+ toUnderlying: (from: Address, amount: bigint) => bigint;
47
+ }): Promise<PathLossRate | undefined>;
48
+ //#endregion
49
+ export { LegProbe, collectPriceImpact, lossRate, startProbe };
@@ -3,6 +3,7 @@ import { MultiCall } from "../../../types/transactions.js";
3
3
  import { OnchainSDK } from "../../../OnchainSDK.js";
4
4
  import { CreditAccountSlice } from "../types.js";
5
5
  import "../../../index.js";
6
+ import { LegProbe } from "./price-impact.js";
6
7
  import { Address } from "viem";
7
8
  //#region src/onchain/accounts/intents/utils/router-path.d.ts
8
9
  /** One routed conversion leg. */
@@ -12,6 +13,14 @@ interface SwapLeg {
12
13
  /** Conservative output — the pathfinder floor after slippage. */
13
14
  minAmount: bigint;
14
15
  calls: MultiCall[];
16
+ /**
17
+ * The marginal-price quote this leg is measured against, already in flight.
18
+ *
19
+ * Produced here, not by the caller, so the basket cannot drift from the trade
20
+ * it prices and the quote is always fired before the leg is awaited.
21
+ * `undefined` where there is nothing to measure.
22
+ */
23
+ probe: LegProbe | undefined;
15
24
  }
16
25
  /** A routed leg that also projects the balances it leaves behind. */
17
26
  interface OpenStrategyLeg extends SwapLeg {