@gearbox-protocol/sdk 16.0.0-next.51 → 16.0.0-next.52

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 (73) hide show
  1. package/dist/cjs/model/index.js +1 -0
  2. package/dist/cjs/model/result.js +10 -0
  3. package/dist/cjs/onchain/accounts/intents/leverage-band.js +1 -1
  4. package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +8 -19
  5. package/dist/cjs/onchain/accounts/intents/open-strategy.js +1 -1
  6. package/dist/cjs/onchain/accounts/intents/realize.js +1 -1
  7. package/dist/cjs/onchain/accounts/intents/testing/market.js +6 -5
  8. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +21 -74
  9. package/dist/cjs/onchain/accounts/intents/utils/pick-token.js +1 -1
  10. package/dist/cjs/onchain/accounts/intents/utils/price-impact.js +2 -2
  11. package/dist/cjs/onchain/accounts/intents/utils/router-path.js +1 -1
  12. package/dist/cjs/onchain/accounts/intents/view.js +1 -1
  13. package/dist/cjs/onchain/accounts/liquidations/LiquidationsService.js +3 -3
  14. package/dist/cjs/onchain/index.js +1 -1
  15. package/dist/cjs/onchain/market/MarketSuite.js +0 -28
  16. package/dist/cjs/onchain/market/credit/collateralUtils.js +2 -2
  17. package/dist/cjs/onchain/market/index.js +1 -1
  18. package/dist/cjs/onchain/market/oracle/PriceOracleBaseContract.js +66 -13
  19. package/dist/cjs/onchain/market/oracle/TestPriceOracle.mock.js +215 -0
  20. package/dist/cjs/onchain/market/oracle/index.js +1 -1
  21. package/dist/cjs/onchain/positions/PositionsService.js +5 -7
  22. package/dist/cjs/onchain/positions/calcHealthFactor.js +4 -3
  23. package/dist/cjs/onchain/router/AbstractRouterContract.js +2 -24
  24. package/dist/cjs/onchain/router/RouterV310Contract.js +1 -12
  25. package/dist/cjs/preview/preview/buildDelayedStrategyPositionOperationPreview.js +26 -38
  26. package/dist/cjs/preview/preview/previewAdjustStrategyPosition.js +2 -3
  27. package/dist/cjs/preview/preview/previewExitOrRepayStrategyPosition.js +4 -5
  28. package/dist/cjs/preview/preview/previewOpenStrategyPosition.js +3 -7
  29. package/dist/cjs/preview/preview/previewOperation.js +1 -2
  30. package/dist/esm/model/index.js +2 -2
  31. package/dist/esm/model/result.js +10 -1
  32. package/dist/esm/onchain/accounts/intents/leverage-band.js +1 -1
  33. package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +8 -19
  34. package/dist/esm/onchain/accounts/intents/open-strategy.js +1 -1
  35. package/dist/esm/onchain/accounts/intents/realize.js +1 -1
  36. package/dist/esm/onchain/accounts/intents/testing/market.js +6 -5
  37. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +22 -75
  38. package/dist/esm/onchain/accounts/intents/utils/pick-token.js +1 -1
  39. package/dist/esm/onchain/accounts/intents/utils/price-impact.js +2 -2
  40. package/dist/esm/onchain/accounts/intents/utils/router-path.js +1 -1
  41. package/dist/esm/onchain/accounts/intents/view.js +1 -1
  42. package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +3 -3
  43. package/dist/esm/onchain/index.js +1 -1
  44. package/dist/esm/onchain/market/MarketSuite.js +0 -28
  45. package/dist/esm/onchain/market/credit/collateralUtils.js +2 -2
  46. package/dist/esm/onchain/market/index.js +1 -1
  47. package/dist/esm/onchain/market/oracle/PriceOracleBaseContract.js +66 -13
  48. package/dist/esm/onchain/market/oracle/TestPriceOracle.mock.js +213 -0
  49. package/dist/esm/onchain/market/oracle/index.js +1 -1
  50. package/dist/esm/onchain/positions/PositionsService.js +5 -7
  51. package/dist/esm/onchain/positions/calcHealthFactor.js +4 -3
  52. package/dist/esm/onchain/router/AbstractRouterContract.js +2 -24
  53. package/dist/esm/onchain/router/RouterV310Contract.js +1 -12
  54. package/dist/esm/preview/preview/buildDelayedStrategyPositionOperationPreview.js +26 -38
  55. package/dist/esm/preview/preview/previewAdjustStrategyPosition.js +2 -3
  56. package/dist/esm/preview/preview/previewExitOrRepayStrategyPosition.js +4 -5
  57. package/dist/esm/preview/preview/previewOpenStrategyPosition.js +3 -7
  58. package/dist/esm/preview/preview/previewOperation.js +1 -2
  59. package/dist/types/model/index.d.ts +2 -2
  60. package/dist/types/model/previews.d.ts +4 -3
  61. package/dist/types/model/result.d.ts +16 -1
  62. package/dist/types/onchain/accounts/intents/maxWithdrawCollateral.d.ts +5 -3
  63. package/dist/types/onchain/accounts/intents/testing/market.d.ts +5 -1
  64. package/dist/types/onchain/accounts/intents/testing/sdk-mock.d.ts +1 -2
  65. package/dist/types/onchain/index.d.ts +2 -2
  66. package/dist/types/onchain/market/MarketSuite.d.ts +2 -29
  67. package/dist/types/onchain/market/index.d.ts +2 -2
  68. package/dist/types/onchain/market/oracle/PriceOracleBaseContract.d.ts +15 -5
  69. package/dist/types/onchain/market/oracle/types.d.ts +40 -28
  70. package/dist/types/onchain/positions/calcHealthFactor.d.ts +7 -3
  71. package/dist/types/onchain/router/AbstractRouterContract.d.ts +0 -4
  72. package/dist/types/preview/preview/buildDelayedStrategyPositionOperationPreview.d.ts +4 -6
  73. package/package.json +2 -10
@@ -0,0 +1,215 @@
1
+ const require_abi_310_generated = require("../../../abi/310/generated.js");
2
+ const require_onchain_chain_chains = require("../../chain/chains.js");
3
+ require("../../chain/index.js");
4
+ require("../../constants/address-provider.js");
5
+ require("../../constants/math.js");
6
+ require("../../constants/index.js");
7
+ const require_onchain_utils_formatter = require("../../utils/formatter.js");
8
+ require("../../utils/index.js");
9
+ const require_onchain_base_ChainContractsRegister = require("../../base/ChainContractsRegister.js");
10
+ require("../../base/index.js");
11
+ const require_onchain_market_pricefeeds_PriceFeedRef = require("../pricefeeds/PriceFeedRef.js");
12
+ require("../pricefeeds/index.js");
13
+ const require_onchain_market_oracle_PriceOracleBaseContract = require("./PriceOracleBaseContract.js");
14
+ let viem = require("viem");
15
+ //#region src/onchain/market/oracle/TestPriceOracle.mock.ts
16
+ /**
17
+ * Well-known mainnet tokens for tests. The oracle prefills their metadata;
18
+ * a seed can then be as small as `{ price: 2000 }`.
19
+ **/
20
+ const MockTokens = {
21
+ WETH: (0, viem.getAddress)("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
22
+ USDC: (0, viem.getAddress)("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"),
23
+ DAI: (0, viem.getAddress)("0x6B175474E89094C44Da98b954EedeAC495271d0F"),
24
+ cbETH: (0, viem.getAddress)("0xBe9895146f7AF43049ca1c1AE358B0541Ea49704"),
25
+ dcUSDC: (0, viem.getAddress)("0x50A9C808cd114E8fEA72f03aE2B1A8825677D56D"),
26
+ ACRED: (0, viem.getAddress)("0x17418038ecF73BA4026c4f428547BF099706F27B"),
27
+ srpACRED_USDC: (0, viem.getAddress)("0xe4a38b653B2580C9D72a50F190Ddd6E2d2D2a412")
28
+ };
29
+ const MOCK_TOKEN_META = {
30
+ [MockTokens.WETH]: {
31
+ decimals: 18,
32
+ symbol: "WETH",
33
+ name: "Wrapped Ether"
34
+ },
35
+ [MockTokens.USDC]: {
36
+ decimals: 6,
37
+ symbol: "USDC",
38
+ name: "USD Coin"
39
+ },
40
+ [MockTokens.DAI]: {
41
+ decimals: 18,
42
+ symbol: "DAI",
43
+ name: "Dai Stablecoin"
44
+ },
45
+ [MockTokens.cbETH]: {
46
+ decimals: 18,
47
+ symbol: "cbETH",
48
+ name: "Coinbase Wrapped Staked ETH"
49
+ },
50
+ [MockTokens.dcUSDC]: {
51
+ decimals: 6,
52
+ symbol: "dcUSDC",
53
+ name: "Default compliant USD Coin"
54
+ },
55
+ [MockTokens.ACRED]: {
56
+ decimals: 6,
57
+ symbol: "ACRED",
58
+ name: "Apollo Diversified Credit Securitize Fund"
59
+ },
60
+ [MockTokens.srpACRED_USDC]: {
61
+ decimals: 6,
62
+ symbol: "srpACRED_USDC",
63
+ name: "Securitize pending redemption Apollo Diversified Credit Securitize Fund to USD Coin"
64
+ }
65
+ };
66
+ const TEST_ORACLE_ADDRESS = (0, viem.getAddress)("0x040ac1e000000000000000000000000000000310");
67
+ const FAILED_ANSWER = {
68
+ price: 0n,
69
+ success: false,
70
+ updatedAt: 0n
71
+ };
72
+ /**
73
+ * Register whose client rejects any RPC request: the oracle never talks to a
74
+ * node. `addressProvider.getAddress` answers `AP_WETH_TOKEN` with mainnet WETH
75
+ * so `#priceableToken` and `safeConvertMinUSD` exercise their real native
76
+ * branches.
77
+ **/
78
+ var TestOracleSdk = class extends require_onchain_base_ChainContractsRegister.ChainContractsRegister {
79
+ addressProvider = { getAddress: (contract, version) => {
80
+ if (contract === "WETH_TOKEN") return MockTokens.WETH;
81
+ throw new Error(`Address ${contract}, version: ${version} not found`);
82
+ } };
83
+ priceFeeds = { generatePriceFeedsUpdateTxs: () => {
84
+ throw new Error("TestPriceOracle: no priceFeeds");
85
+ } };
86
+ };
87
+ /**
88
+ * A real {@link PriceOracleBaseContract} seeded from plain records, for tests.
89
+ *
90
+ * Conversion, safe-price fallback, and native-through-WETH all run the
91
+ * production code. Feed-tree methods (`priceFeedData`, `priceUpdatesFor*`, …)
92
+ * are not wired and throw if touched.
93
+ **/
94
+ var TestPriceOracle = class extends require_onchain_market_oracle_PriceOracleBaseContract.PriceOracleBaseContract {
95
+ constructor(tokens = {}) {
96
+ const register = new TestOracleSdk((0, viem.createPublicClient)({
97
+ chain: require_onchain_chain_chains.getChain("Mainnet"),
98
+ transport: (0, viem.custom)({ request: async () => {
99
+ throw new Error("not implemented");
100
+ } })
101
+ }));
102
+ super(register, {
103
+ abi: require_abi_310_generated.iPriceOracleV310Abi,
104
+ addr: TEST_ORACLE_ADDRESS,
105
+ name: "TestPriceOracle"
106
+ }, {
107
+ priceFeedMap: [],
108
+ priceFeedTree: []
109
+ });
110
+ for (const [token, meta] of Object.entries(MOCK_TOKEN_META)) {
111
+ const addr = (0, viem.getAddress)(token);
112
+ this.register.tokensMeta.upsert(addr, {
113
+ addr,
114
+ ...meta
115
+ });
116
+ }
117
+ for (const [token, cfg] of Object.entries(tokens)) this.addToken(token, cfg);
118
+ }
119
+ /**
120
+ * Registers token meta and optional feed answers. Chainable, like all
121
+ * modifiers.
122
+ **/
123
+ addToken(token, cfg) {
124
+ const addr = (0, viem.getAddress)(token);
125
+ const known = MOCK_TOKEN_META[addr];
126
+ const symbol = cfg.symbol ?? known?.symbol ?? `T_${addr.slice(2, 8)}`;
127
+ this.register.tokensMeta.upsert(addr, {
128
+ addr,
129
+ symbol,
130
+ name: cfg.name ?? known?.name ?? symbol,
131
+ decimals: cfg.decimals ?? known?.decimals ?? 18
132
+ });
133
+ if (cfg.price !== void 0) this.setMainPrice(addr, cfg.price);
134
+ if (cfg.reservePrice !== void 0) this.setReservePrice(addr, cfg.reservePrice);
135
+ return this;
136
+ }
137
+ setMainPrice(token, price) {
138
+ this.#setAnswer(token, "main", rawPrice(price));
139
+ return this;
140
+ }
141
+ setReservePrice(token, price) {
142
+ this.#setAnswer(token, "reserve", rawPrice(price));
143
+ return this;
144
+ }
145
+ /**
146
+ * Feed stays configured, its answer failed — {@link PriceFeedAnswerMap.price}
147
+ * throws. Distinct from {@link removeMainFeed}.
148
+ **/
149
+ failMainAnswer(token) {
150
+ this.#failAnswer(token, "main");
151
+ return this;
152
+ }
153
+ /**
154
+ * Feed stays configured, its answer failed. Distinct from
155
+ * {@link removeReserveFeed}: `safeConvertMinUSD` treats a present-but-failed
156
+ * reserve feed as an error, and a missing one as an untrusted 0.
157
+ **/
158
+ failReserveAnswer(token) {
159
+ this.#failAnswer(token, "reserve");
160
+ return this;
161
+ }
162
+ /**
163
+ * No main feed at all: distinct from a failed answer.
164
+ **/
165
+ removeMainFeed(token) {
166
+ this.mainPriceFeeds.delete(token);
167
+ this.mainPrices.delete(token);
168
+ return this;
169
+ }
170
+ /**
171
+ * No reserve feed at all: distinct from a failed answer, and what
172
+ * `safeConvertMinUSD` treats as an untrusted token (value 0, no error).
173
+ **/
174
+ removeReserveFeed(token) {
175
+ this.reservePriceFeeds.delete(token);
176
+ this.reservePrices.delete(token);
177
+ return this;
178
+ }
179
+ async updateAndConvert(_from, _to, _amount) {
180
+ throw new Error("TestPriceOracle: updateAndConvert needs a node");
181
+ }
182
+ #setAnswer(token, kind, price) {
183
+ this.#ensureFeed(token, kind);
184
+ this.#answers(kind).upsert(token, {
185
+ price,
186
+ success: true,
187
+ updatedAt: 0n
188
+ });
189
+ }
190
+ #failAnswer(token, kind) {
191
+ this.#ensureFeed(token, kind);
192
+ this.#answers(kind).upsert(token, FAILED_ANSWER);
193
+ }
194
+ #ensureFeed(token, kind) {
195
+ const feeds = kind === "main" ? this.mainPriceFeeds : this.reservePriceFeeds;
196
+ if (!feeds.has(token)) feeds.upsert(token, new require_onchain_market_pricefeeds_PriceFeedRef.PriceFeedRef(this.register, feedAddr(token, kind), 0));
197
+ }
198
+ #answers(kind) {
199
+ return kind === "main" ? this.mainPrices : this.reservePrices;
200
+ }
201
+ };
202
+ /** Human USD → 8-decimal fixed point; bigint passes through. */
203
+ function rawPrice(price) {
204
+ return typeof price === "bigint" ? price : require_onchain_utils_formatter.toBN(String(price), 8);
205
+ }
206
+ /** Deterministic unused address per token feed; never resolved. */
207
+ function feedAddr(token, kind) {
208
+ const bytes = (0, viem.hexToBytes)((0, viem.getAddress)(token));
209
+ bytes[0] = kind === "main" ? 254 : 253;
210
+ return (0, viem.getAddress)((0, viem.bytesToHex)(bytes));
211
+ }
212
+ //#endregion
213
+ exports.MockTokens = MockTokens;
214
+ exports.TEST_ORACLE_ADDRESS = TEST_ORACLE_ADDRESS;
215
+ exports.TestPriceOracle = TestPriceOracle;
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_market_oracle_collateralPriceInUnderlying = require("./collateralPriceInUnderlying.js");
3
+ const require_onchain_market_oracle_errors = require("./errors.js");
3
4
  const require_onchain_market_oracle_PriceOracleV310Contract = require("./PriceOracleV310Contract.js");
4
5
  const require_onchain_market_oracle_createPriceOracle = require("./createPriceOracle.js");
5
- const require_onchain_market_oracle_errors = require("./errors.js");
6
6
  require("./types.js");
7
7
  exports.PriceOracleV310Contract = require_onchain_market_oracle_PriceOracleV310Contract.PriceOracleV310Contract;
8
8
  exports.collateralPriceInUnderlying = require_onchain_market_oracle_collateralPriceInUnderlying.collateralPriceInUnderlying;
@@ -293,15 +293,12 @@ var PositionsService = class extends require_onchain_base_SDKConstruct.SDKConstr
293
293
  quota: priceOracle.toTokenAmount(market.underlying, t.quota),
294
294
  withdrawals: withdrawals.get(t.token) ?? []
295
295
  });
296
- if (recomputeTotals) {
297
- const usd = priceOracle.safeConvertToUSD(t.token, t.balance) || 0n;
298
- totalValueUSD += usd;
299
- }
296
+ if (recomputeTotals) totalValueUSD += priceOracle.safeConvertToUSD(t.token, t.balance).value;
300
297
  }
301
- if (recomputeTotals) totalValue = market.valueInUnderlying(ca.tokens.map((t) => ({
298
+ if (recomputeTotals) totalValue = priceOracle.safeConvertAssets(ca.tokens.map((t) => ({
302
299
  token: t.token,
303
300
  balance: t.balance
304
- }))).value;
301
+ })), market.underlying).value;
305
302
  const snapshot = {
306
303
  ...require_onchain_positions_types.accountSnapshotFromCreditAccountData(ca),
307
304
  totalValue
@@ -309,7 +306,8 @@ var PositionsService = class extends require_onchain_base_SDKConstruct.SDKConstr
309
306
  const borrowRate = this.borrowRate(snapshot);
310
307
  const timeToLiquidation = this.timeToLiquidation(snapshot);
311
308
  const liquidationPrice = this.liquidationPrice(snapshot);
312
- const totalDebtUSD = priceFailed ? priceOracle.safeConvertToUSD(market.underlying, totalDebtValue) ?? 0n : ca.totalDebtUSD;
309
+ let totalDebtUSD = ca.totalDebtUSD;
310
+ if (priceFailed) totalDebtUSD = priceOracle.safeConvertToUSD(market.underlying, totalDebtValue).value;
313
311
  return {
314
312
  kind: "strategy",
315
313
  chainId: this.sdk.chainId,
@@ -24,10 +24,11 @@ function calcHealthFactor(props) {
24
24
  const active = new require_onchain_utils_AddressMap.AddressMap(Object.entries(activeQuotas));
25
25
  const priceOf = (token, forCollateral) => {
26
26
  const main = pricesByToken.get(token);
27
- if (!safePrices || !forCollateral) return main;
27
+ if (!safePrices || !forCollateral || (0, viem.isAddressEqual)(token, underlying)) return main;
28
+ if (main === void 0) return;
28
29
  const reserve = reservePricesByToken.get(token);
29
- if (main !== void 0 && reserve !== void 0) return require_onchain_utils_bigint_math.BigIntMath.min(main, reserve);
30
- return main ?? reserve;
30
+ if (reserve === void 0) return 0n;
31
+ return require_onchain_utils_bigint_math.BigIntMath.min(main, reserve);
31
32
  };
32
33
  const convertToUSD = (token, amount, forCollateral = false) => {
33
34
  const price = priceOf(token, forCollateral);
@@ -86,7 +86,7 @@ var AbstractRouterContract = class extends require_onchain_base_BaseContract.Bas
86
86
  leftoverBalances.upsert(token, require_onchain_router_helpers.limitLeftover(balance, token) ?? balance);
87
87
  if (isEnabled && !keepAssets.has(token)) usdBalances.push({
88
88
  token,
89
- balance: this.safeConvertToUSD(priceOracle, token, balance)
89
+ balance: priceOracle.safeConvertToUSD(token, balance).value
90
90
  });
91
91
  }
92
92
  usdBalances.sort((a, b) => {
@@ -99,7 +99,7 @@ var AbstractRouterContract = class extends require_onchain_base_BaseContract.Bas
99
99
  const lt = this.sdk.marketRegister.findCreditManager(ca.creditManager).creditManager.liquidationThresholds.mustGet(highestToken.token);
100
100
  const requiredDebtUSD = ca.totalDebtUSD * require_onchain_constants_math.PERCENTAGE_FACTOR / BigInt(lt);
101
101
  if (highestToken.balance < requiredDebtUSD) return;
102
- const tokenAmount = this.safeConvertFromUSD(priceOracle, highestToken.token, requiredDebtUSD);
102
+ const tokenAmount = priceOracle.safeConvertFromUSD(highestToken.token, requiredDebtUSD).value;
103
103
  if (tokenAmount === 0n) return;
104
104
  let leftoverBalance = leftoverBalances.get(highestToken.token) ?? 0n;
105
105
  leftoverBalance -= tokenAmount;
@@ -114,28 +114,6 @@ var AbstractRouterContract = class extends require_onchain_base_BaseContract.Bas
114
114
  tokensToClaim: new require_onchain_utils_AssetsMap.AssetsMap()
115
115
  };
116
116
  }
117
- safeConvertToUSD(priceOracle, token, balance) {
118
- try {
119
- return priceOracle.convertToUSD(token, balance);
120
- } catch {
121
- try {
122
- return priceOracle.convertToUSD(token, balance, true);
123
- } catch {
124
- return 0n;
125
- }
126
- }
127
- }
128
- safeConvertFromUSD(priceOracle, token, balance) {
129
- try {
130
- return priceOracle.convertFromUSD(token, balance);
131
- } catch {
132
- try {
133
- return priceOracle.convertFromUSD(token, balance, true);
134
- } catch {
135
- return 0n;
136
- }
137
- }
138
- }
139
117
  };
140
118
  //#endregion
141
119
  exports.AbstractRouterContract = AbstractRouterContract;
@@ -228,7 +228,7 @@ var RouterV310Contract = class extends require_onchain_router_AbstractRouterCont
228
228
  }).map(({ token, balance }) => {
229
229
  return {
230
230
  token,
231
- balance: this.#convertToUSDForSort(priceOracle, token, balance)
231
+ balance: priceOracle.safeConvertToUSD(token, balance).value
232
232
  };
233
233
  }).sort((a, b) => {
234
234
  return a.balance > b.balance ? -1 : 1;
@@ -241,17 +241,6 @@ var RouterV310Contract = class extends require_onchain_router_AbstractRouterCont
241
241
  for (const [token, numSplits] of this.#numSplits.entries()) map.upsert(token, numSplits);
242
242
  return (token) => map.get(token) ?? 1n;
243
243
  }
244
- /**
245
- * Tries to get some value even when prices are broken, since it's only needed for sorting
246
- * @param oracle
247
- * @param token
248
- * @param amount
249
- * @returns
250
- */
251
- #convertToUSDForSort(oracle, token, amount) {
252
- const scale = 10n ** BigInt(this.tokensMeta.get(token)?.decimals ?? 0);
253
- return amount * (oracle.mainPrices.get(token)?.price || oracle.reservePrices.get(token)?.price || scale) / scale;
254
- }
255
244
  #debugTokenData(tData) {
256
245
  return tData.map((t) => ({
257
246
  token: this.labelAddress(t.token),
@@ -4,7 +4,6 @@ const require_onchain_utils_bigint_math = require("../../onchain/utils/bigint-ma
4
4
  const require_onchain_constants_math = require("../../onchain/constants/math.js");
5
5
  const require_model_previews = require("../../model/previews.js");
6
6
  require("../../model/index.js");
7
- const require_onchain_market_oracle_errors = require("../../onchain/market/oracle/errors.js");
8
7
  require("../../onchain/index.js");
9
8
  let viem = require("viem");
10
9
  //#region src/preview/preview/buildDelayedStrategyPositionOperationPreview.ts
@@ -14,10 +13,9 @@ let viem = require("viem");
14
13
  * the claim itself followed by the intent-specific tail
15
14
  *
16
15
  * Pure function: the input states are never mutated and no network access is performed.
17
- * Swaps are estimated with the injected conversion; remaining holdings are
18
- * priced by `MarketSuite.valueInUnderlying`. Tokens that cannot be priced
19
- * contribute nothing and set a non-fatal `unpriceableToken` warning on the
20
- * preview.
16
+ * Swaps and remaining holdings are priced by the market oracle. Tokens that
17
+ * cannot be priced contribute nothing and set a non-fatal `unpriceableToken`
18
+ * warning on the preview.
21
19
  *
22
20
  * The changes (e.g. `totalDebtChange`) are reported relative to the account
23
21
  * state before the whole transaction.
@@ -31,36 +29,26 @@ let viem = require("viem");
31
29
  * @param sdk - Market data source for the position metrics of the resulting
32
30
  * state; read synchronously, no network access.
33
31
  */
34
- function buildDelayedStrategyPositionOperationPreview(afterInstant, before, detected, convert, receivedToken, sdk) {
32
+ function buildDelayedStrategyPositionOperationPreview(afterInstant, before, detected, receivedToken, sdk) {
35
33
  const { request, intent } = detected;
36
34
  const post = afterInstant.clone();
37
- const converter = makeSafeConverter(convert);
35
+ const oracle = sdk.marketRegister.findByCreditManager(post.creditManager).priceOracle;
36
+ let warning;
37
+ const convert = (from, to, amount) => {
38
+ const priced = oracle.safeConvert(from, to, amount);
39
+ warning ??= priced.error;
40
+ return priced.value;
41
+ };
38
42
  const claimed = applyClaim(post, request);
39
43
  const collateralWithdrawn = new require_onchain_utils_AssetsMap.AssetsMap();
40
44
  switch (intent?.type) {
41
- case "CLOSE_ACCOUNT": return buildClosePreview(post, converter, receivedToken, sdk);
45
+ case "CLOSE_ACCOUNT": return buildClosePreview(post, receivedToken, sdk, warning);
42
46
  case "DECREASE_LEVERAGE":
43
- repayFromClaim(post, request.claimToken, converter.convert, claimed);
47
+ repayFromClaim(post, request.claimToken, convert, claimed);
44
48
  break;
45
- case "WITHDRAW_COLLATERAL": applyWithdrawCollateral(post, request, intent, converter, collateralWithdrawn);
49
+ case "WITHDRAW_COLLATERAL": applyWithdrawCollateral(post, request, intent, convert, collateralWithdrawn);
46
50
  }
47
- return buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk);
48
- }
49
- function makeSafeConverter(convert) {
50
- let warning;
51
- return {
52
- convert: (token, to, amount) => {
53
- try {
54
- return convert(token, to, amount);
55
- } catch {
56
- warning ??= require_onchain_market_oracle_errors.unpriceableTokenError(token);
57
- return 0n;
58
- }
59
- },
60
- get warning() {
61
- return warning;
62
- }
63
- };
51
+ return buildAdjustPreview(post, before, collateralWithdrawn, sdk, warning);
64
52
  }
65
53
  /**
66
54
  * Claim step, common to all intents: burns the phantom token (balance and
@@ -106,7 +94,7 @@ function applyClaim(post, request) {
106
94
  * debt with them, but no more than the intent's `debtRepaid` target;
107
95
  * whatever is not spent on repayment stays on the account as underlying.
108
96
  */
109
- function applyWithdrawCollateral(post, request, intent, converter, collateralWithdrawn) {
97
+ function applyWithdrawCollateral(post, request, intent, convert, collateralWithdrawn) {
110
98
  const { withdrawToken, withdrawAmount, debtRepaid } = intent;
111
99
  const { claimToken } = request;
112
100
  const sameToken = (0, viem.isAddressEqual)(withdrawToken, claimToken);
@@ -116,19 +104,19 @@ function applyWithdrawCollateral(post, request, intent, converter, collateralWit
116
104
  const missing = withdrawAmount - fromBalance;
117
105
  if (missing > 0n && !sameToken) {
118
106
  const available = post.balances.getOrZero(claimToken);
119
- const cost = converter.convert(withdrawToken, claimToken, missing);
107
+ const cost = convert(withdrawToken, claimToken, missing);
120
108
  if (cost > 0n && cost <= available) {
121
109
  post.balances.dec(claimToken, cost);
122
110
  withdrawn += missing;
123
111
  } else if (available > 0n) {
124
112
  post.balances.dec(claimToken, available);
125
- withdrawn += converter.convert(claimToken, withdrawToken, available);
113
+ withdrawn += convert(claimToken, withdrawToken, available);
126
114
  }
127
115
  }
128
116
  if (withdrawn > 0n) collateralWithdrawn.upsert(withdrawToken, withdrawn);
129
117
  const remaining = post.balances.getOrZero(claimToken);
130
118
  if (remaining > 0n) {
131
- const proceeds = converter.convert(claimToken, post.underlying, remaining);
119
+ const proceeds = convert(claimToken, post.underlying, remaining);
132
120
  post.balances.dec(claimToken, remaining);
133
121
  post.balances.inc(post.underlying, proceeds);
134
122
  post.repay(require_onchain_utils_bigint_math.BigIntMath.min(proceeds, debtRepaid));
@@ -152,10 +140,10 @@ function repayFromClaim(post, claimToken, convert, amount) {
152
140
  * underlying, the debt is repaid in full and the remainder is withdrawn to
153
141
  * the user as `receivedToken`.
154
142
  */
155
- function buildClosePreview(post, converter, receivedToken, sdk) {
143
+ function buildClosePreview(post, receivedToken, sdk, warning) {
156
144
  const market = sdk.marketRegister.findByCreditManager(post.creditManager);
157
- const priced = market.valueInUnderlying(post.balances.toAssets(), 0n);
158
145
  const oracle = market.priceOracle;
146
+ const priced = oracle.safeConvertAssets(post.balances.toAssets(), market.underlying);
159
147
  const suite = sdk.marketRegister.findCreditManager(post.creditManager);
160
148
  return {
161
149
  operation: "CloseCreditAccount",
@@ -171,15 +159,15 @@ function buildClosePreview(post, converter, receivedToken, sdk) {
171
159
  name: suite.accountStrategyName(post.creditAccount),
172
160
  targetCollateral: suite.accountTargetCollateral(post.creditAccount),
173
161
  receivedAmount: oracle.toTokenAmount(receivedToken, require_onchain_utils_bigint_math.BigIntMath.max(priced.value - post.totalDebt, 0n)),
174
- warning: converter.warning ?? (priced.unpriceable ? require_onchain_market_oracle_errors.unpriceableTokenError(priced.unpriceable) : void 0)
162
+ warning: warning ?? priced.error
175
163
  };
176
164
  }
177
- function buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk) {
165
+ function buildAdjustPreview(post, before, collateralWithdrawn, sdk, warning) {
178
166
  const market = sdk.marketRegister.findByCreditManager(post.creditManager);
179
- const priced = market.valueInUnderlying(post.balances.toAssets());
167
+ const oracle = market.priceOracle;
168
+ const priced = oracle.safeConvertAssets(post.balances.toAssets(), market.underlying);
180
169
  const snap = post.toSnapshot(priced.value);
181
170
  const suite = sdk.marketRegister.findCreditManager(post.creditManager);
182
- const oracle = market.priceOracle;
183
171
  return {
184
172
  operation: "AdjustCreditAccount",
185
173
  ...require_model_previews.asEstimated(sdk.positions.projection(snap, { availableLiquidityChange: before.totalDebt - post.totalDebt })),
@@ -194,7 +182,7 @@ function buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk) {
194
182
  ...oracle.toAmount(market.underlying, q.balance)
195
183
  })),
196
184
  assetsChange: post.balances.difference(before.balances).toAssets(require_onchain_constants_math.DUST_THRESHOLD).map((a) => oracle.toTokenAmount(a.token, a.balance)),
197
- warning: converter.warning ?? (priced.unpriceable ? require_onchain_market_oracle_errors.unpriceableTokenError(priced.unpriceable) : void 0)
185
+ warning: warning ?? priced.error
198
186
  };
199
187
  }
200
188
  //#endregion
@@ -3,7 +3,6 @@ const require_onchain_constants_address_provider = require("../../onchain/consta
3
3
  const require_onchain_constants_math = require("../../onchain/constants/math.js");
4
4
  const require_model_previews = require("../../model/previews.js");
5
5
  require("../../model/index.js");
6
- const require_onchain_market_oracle_errors = require("../../onchain/market/oracle/errors.js");
7
6
  require("../../onchain/index.js");
8
7
  const require_preview_preview_replayMulticall = require("./replayMulticall.js");
9
8
  const require_preview_preview_unwrapNativeCollateral = require("./unwrapNativeCollateral.js");
@@ -26,8 +25,8 @@ function previewAdjustStrategyPosition(input, operation, options) {
26
25
  const { assets: collateralAdded, warning: unwrapWarning } = require_preview_preview_unwrapNativeCollateral.unwrapNativeCollateral(after.collateralAdded.toAssets(), value, sdk.addressProvider.getAddress(require_onchain_constants_address_provider.AP_WETH_TOKEN, 0));
27
26
  warning ??= unwrapWarning;
28
27
  const assetsChange = account.balances.difference(before.balances).toAssets(require_onchain_constants_math.DUST_THRESHOLD);
29
- const priced = market.valueInUnderlying(account.balances.toAssets());
30
- if (priced.unpriceable) warning ??= require_onchain_market_oracle_errors.unpriceableTokenError(priced.unpriceable);
28
+ const priced = oracle.safeConvertAssets(account.balances.toAssets(), market.underlying);
29
+ warning ??= priced.error;
31
30
  const snap = account.toSnapshot(priced.value);
32
31
  return {
33
32
  operation: "AdjustCreditAccount",
@@ -3,7 +3,6 @@ const require_onchain_constants_address_provider = require("../../onchain/consta
3
3
  require("../../onchain/constants/math.js");
4
4
  const require_model_previews = require("../../model/previews.js");
5
5
  require("../../model/index.js");
6
- const require_onchain_market_oracle_errors = require("../../onchain/market/oracle/errors.js");
7
6
  require("../../onchain/index.js");
8
7
  const require_preview_preview_detectCloseOrRepay = require("./detectCloseOrRepay.js");
9
8
  const require_preview_preview_replayMulticall = require("./replayMulticall.js");
@@ -29,8 +28,8 @@ function previewCloseCreditAccount(input, operation, permanent, replay) {
29
28
  const { before, after, warning: replayWarning } = replay;
30
29
  const account = after.account;
31
30
  let warning = replayWarning;
32
- const priced = market.valueInUnderlying(account.balances.toAssets());
33
- if (priced.unpriceable) warning ??= require_onchain_market_oracle_errors.unpriceableTokenError(priced.unpriceable);
31
+ const priced = market.priceOracle.safeConvertAssets(account.balances.toAssets(), market.underlying);
32
+ warning ??= priced.error;
34
33
  const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
35
34
  let receivedToken = market.underlying;
36
35
  for (const m of operation.multicall) if (m.operation === "WithdrawCollateral" && m.amount === 115792089237316195423570985008687907853269984665640564039457584007913129639935n) {
@@ -60,8 +59,8 @@ function previewRepayCreditAccount(input, operation, permanent, replay) {
60
59
  const account = after.account;
61
60
  const { assets: collateralAdded, warning: unwrapWarning } = require_preview_preview_unwrapNativeCollateral.unwrapNativeCollateral(after.collateralAdded.toAssets(), value, sdk.addressProvider.getAddress(require_onchain_constants_address_provider.AP_WETH_TOKEN, 0));
62
61
  let warning = replayWarning ?? unwrapWarning;
63
- const priced = market.valueInUnderlying(account.balances.toAssets());
64
- if (priced.unpriceable) warning ??= require_onchain_market_oracle_errors.unpriceableTokenError(priced.unpriceable);
62
+ const priced = market.priceOracle.safeConvertAssets(account.balances.toAssets(), market.underlying);
63
+ warning ??= priced.error;
65
64
  const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
66
65
  return {
67
66
  operation: "RepayCreditAccount",
@@ -2,7 +2,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_constants_address_provider = require("../../onchain/constants/address-provider.js");
3
3
  const require_model_previews = require("../../model/previews.js");
4
4
  require("../../model/index.js");
5
- const require_onchain_market_oracle_errors = require("../../onchain/market/oracle/errors.js");
6
5
  require("../../onchain/index.js");
7
6
  const require_preview_preview_CreditAccountState = require("./CreditAccountState.js");
8
7
  const require_preview_preview_replayInnerOperations = require("./replayInnerOperations.js");
@@ -17,12 +16,9 @@ function previewOpenStrategyPosition(input, operation) {
17
16
  const account = state.account;
18
17
  let priceWarning;
19
18
  const netValue = state.collateralAdded.sum((token, balance) => {
20
- try {
21
- return oracle.convert(token, market.underlying, balance);
22
- } catch {
23
- priceWarning ??= require_onchain_market_oracle_errors.unpriceableTokenError(token);
24
- return 0n;
25
- }
19
+ const priced = oracle.safeConvert(token, market.underlying, balance);
20
+ priceWarning ??= priced.error;
21
+ return priced.value;
26
22
  });
27
23
  const { assets: collateral, warning: unwrapWarning } = require_preview_preview_unwrapNativeCollateral.unwrapNativeCollateral(state.collateralAdded.toAssets(), value, sdk.addressProvider.getAddress(require_onchain_constants_address_provider.AP_WETH_TOKEN, 0));
28
24
  warning ??= unwrapWarning ?? priceWarning;
@@ -81,7 +81,6 @@ async function previewMulticallOperation(input, operation, options) {
81
81
  }
82
82
  const { before, after } = require_preview_preview_replayMulticall.replayMulticall(sdk, operation, options);
83
83
  const market = sdk.marketRegister.findByCreditManager(operation.creditManager);
84
- const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
85
84
  const meta = sdk.tokensMeta.get(market.underlying);
86
85
  const receivedToken = meta && sdk.tokensMeta.isRWAUnderlying(meta) ? meta.asset : market.underlying;
87
86
  const suite = sdk.marketRegister.findCreditManager(operation.creditManager);
@@ -94,7 +93,7 @@ async function previewMulticallOperation(input, operation, options) {
94
93
  intent: delayed.intent,
95
94
  estClaimableAt: require_preview_preview_estimateClaimableAt.estimateClaimableAt(sdk, delayed.request.phantomToken),
96
95
  instantPreview,
97
- delayedPreview: require_preview_preview_buildDelayedStrategyPositionOperationPreview.buildDelayedStrategyPositionOperationPreview(after.account, before, delayed, convert, receivedToken, sdk)
96
+ delayedPreview: require_preview_preview_buildDelayedStrategyPositionOperationPreview.buildDelayedStrategyPositionOperationPreview(after.account, before, delayed, receivedToken, sdk)
98
97
  });
99
98
  }
100
99
  //#endregion
@@ -20,7 +20,7 @@ import { asEstimated } from "./previews.js";
20
20
  import "./primitives.js";
21
21
  import "./response.js";
22
22
  import { chainFailedSchema, chainMetadataSchema, chainSucceededSchema, dataSourceSchema, responseMetadataSchema, responseSchema } from "./response.schema.js";
23
- import { isSDKError, sdkErr, sdkOk } from "./result.js";
23
+ import { isSDKError, safeValue, sdkErr, sdkOk } from "./result.js";
24
24
  import "./withdrawals.js";
25
25
  import { positionClaimableWithdrawalSchema, positionPendingWithdrawalSchema, positionWithdrawalsSchema, withdrawalOutputAmountSchema } from "./withdrawals.schema.js";
26
- export { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, curatorNameSchema, curatorSchema, dataSourceSchema, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, instantReceivedAssetSchema, isFilterSet, isSDKError, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, withdrawalOutputAmountSchema };
26
+ export { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, curatorNameSchema, curatorSchema, dataSourceSchema, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, instantReceivedAssetSchema, isFilterSet, isSDKError, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, withdrawalOutputAmountSchema };
@@ -1,4 +1,13 @@
1
1
  //#region src/model/result.ts
2
+ /**
3
+ * Builds a {@link SafeValue}. Omits `error` when the value was not degraded.
4
+ **/
5
+ function safeValue(value, error) {
6
+ return error === void 0 ? { value } : {
7
+ value,
8
+ error
9
+ };
10
+ }
2
11
  /** The success half, built. */
3
12
  function sdkOk(data) {
4
13
  return {
@@ -21,4 +30,4 @@ function isSDKError(answer) {
21
30
  return !answer.ok;
22
31
  }
23
32
  //#endregion
24
- export { isSDKError, sdkErr, sdkOk };
33
+ export { isSDKError, safeValue, sdkErr, sdkOk };
@@ -36,7 +36,7 @@ function calcLeverageBand({ sdk, creditManager, collateral, targetHF }) {
36
36
  if (!target) return;
37
37
  const ceiling = suite.creditManager.maxLeverage(target, targetHF);
38
38
  const underlying = market.pool.underlying;
39
- const convert = (from, to, amount) => market.priceOracle.safeConvert(from, to, amount) ?? 0n;
39
+ const convert = (from, to, amount) => market.priceOracle.safeConvert(from, to, amount).value;
40
40
  const netValue = collateral.reduce((acc, a) => acc + convert(a.token, underlying, a.balance), 0n);
41
41
  if (netValue <= 0n) return {
42
42
  min: 1,