@strkfarm/sdk 2.0.0-dev.29 → 2.0.0-dev.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.
package/dist/index.js CHANGED
@@ -6215,7 +6215,7 @@ var EkuboQuoter = class _EkuboQuoter {
6215
6215
  async _callQuoterApi(fromToken, toToken, amount, retry = 0) {
6216
6216
  try {
6217
6217
  const url = this.ENDPOINT.replace("{{AMOUNT}}", amount.toWei()).replace("{{TOKEN_FROM_ADDRESS}}", fromToken).replace("{{TOKEN_TO_ADDRESS}}", toToken);
6218
- logger.verbose(`EkuboQuoter::_callQuoterApi url: ${url}`);
6218
+ logger.info(`EkuboQuoter::_callQuoterApi url: ${url}`);
6219
6219
  const quote = await import_axios6.default.get(url);
6220
6220
  return quote.data;
6221
6221
  } catch (error) {
@@ -8085,6 +8085,7 @@ var vesu_rebalance_abi_default = [
8085
8085
  var CacheClass = class {
8086
8086
  constructor() {
8087
8087
  this.cache = /* @__PURE__ */ new Map();
8088
+ this.isCacheEnabled = true;
8088
8089
  }
8089
8090
  setCache(key, data, ttl = 6e4) {
8090
8091
  const timestamp = Date.now();
@@ -8092,7 +8093,7 @@ var CacheClass = class {
8092
8093
  }
8093
8094
  getCache(key) {
8094
8095
  const cachedData = this.cache.get(key);
8095
- if (!cachedData || !this.isCacheValid(key)) {
8096
+ if (!cachedData || !this.isCacheValid(key) || !this.isCacheEnabled) {
8096
8097
  return null;
8097
8098
  }
8098
8099
  return cachedData.data;
@@ -8103,6 +8104,12 @@ var CacheClass = class {
8103
8104
  const { timestamp, ttl } = cachedData;
8104
8105
  return Date.now() - timestamp <= ttl;
8105
8106
  }
8107
+ disableCache() {
8108
+ this.isCacheEnabled = false;
8109
+ }
8110
+ enableCache() {
8111
+ this.isCacheEnabled = true;
8112
+ }
8106
8113
  };
8107
8114
 
8108
8115
  // src/strategies/base-strategy.ts
@@ -28889,7 +28896,7 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
28889
28896
  throw new Error("LTV is 0");
28890
28897
  }
28891
28898
  this.setCache(CACHE_KEY, ltv, 3e5);
28892
- return this.getCache(CACHE_KEY);
28899
+ return ltv;
28893
28900
  }
28894
28901
  async getPositions(config, blockNumber = "latest") {
28895
28902
  if (!this.pricer) {
@@ -28973,6 +28980,9 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
28973
28980
  debtPrice = (await pricer.getPrice(this.config.debt.priceProxySymbol || this.config.debt.symbol)).price;
28974
28981
  }
28975
28982
  logger.verbose(`VesuAdapter::getAssetPrices collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
28983
+ if (isNaN(collateralPrice) || isNaN(debtPrice) || collateralPrice == 0 || debtPrice == 0) {
28984
+ throw new Error(`VesuAdapter::getAssetPrices collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
28985
+ }
28976
28986
  return {
28977
28987
  collateralTokenAmount,
28978
28988
  collateralUSDAmount,
@@ -34611,20 +34621,23 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34611
34621
  }
34612
34622
  _buildZeroAmountSwapsWithWeights(quote, token, reverseRoutes = false) {
34613
34623
  const swaps = quote.splits.map((split) => {
34614
- const routeNodes = split.route.map((_route) => ({
34615
- pool_key: {
34616
- token0: ContractAddr.from(_route.pool_key.token0),
34617
- token1: ContractAddr.from(_route.pool_key.token1),
34618
- fee: _route.pool_key.fee,
34619
- tick_spacing: _route.pool_key.tick_spacing.toString(),
34620
- extension: _route.pool_key.extension
34621
- },
34622
- sqrt_ratio_limit: Web3Number.fromWei(_route.sqrt_ratio_limit, 18),
34623
- skip_ahead: Web3Number.fromWei(_route.skip_ahead, 0)
34624
- }));
34625
- if (reverseRoutes) {
34626
- routeNodes.reverse();
34627
- }
34624
+ let sellToken = token.address;
34625
+ const routeNodes = split.route.map((_route) => {
34626
+ let isSellToken0 = sellToken.eqString(_route.pool_key.token0);
34627
+ isSellToken0 = reverseRoutes ? !isSellToken0 : isSellToken0;
34628
+ sellToken = isSellToken0 ? ContractAddr.from(_route.pool_key.token1) : ContractAddr.from(_route.pool_key.token0);
34629
+ return {
34630
+ pool_key: {
34631
+ token0: ContractAddr.from(_route.pool_key.token0),
34632
+ token1: ContractAddr.from(_route.pool_key.token1),
34633
+ fee: _route.pool_key.fee,
34634
+ tick_spacing: _route.pool_key.tick_spacing.toString(),
34635
+ extension: _route.pool_key.extension
34636
+ },
34637
+ sqrt_ratio_limit: isSellToken0 ? Web3Number.fromWei(MIN_SQRT_RATIO_LIMIT.toString(), 18) : Web3Number.fromWei(MAX_SQRT_RATIO_LIMIT.toString(), 18),
34638
+ skip_ahead: Web3Number.fromWei(_route.skip_ahead, 0)
34639
+ };
34640
+ });
34628
34641
  return {
34629
34642
  route: routeNodes,
34630
34643
  token_amount: {
@@ -34946,6 +34959,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34946
34959
  collateralToken.address.address,
34947
34960
  requiredAmount
34948
34961
  );
34962
+ logger.info(`VesuMultiplyAdapter::_getIncreaseCalldata requiredAmount: ${requiredAmount}`);
34949
34963
  if (marginSwapQuote.price_impact > 0.01) {
34950
34964
  throw new Error(
34951
34965
  `VesuMultiplyAdapter: Margin swap price impact too high (${marginSwapQuote.price_impact})`
@@ -34972,7 +34986,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34972
34986
  legLTV,
34973
34987
  dexPrice
34974
34988
  );
34975
- logger.verbose(
34989
+ logger.info(
34976
34990
  `${_VesuMultiplyAdapter.name}::_getIncreaseCalldata debtAmount: ${debtAmount}, addedCollateral: ${addedCollateral}`
34977
34991
  );
34978
34992
  let leverSwap = [];
@@ -34990,8 +35004,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34990
35004
  collateralToken.address.address,
34991
35005
  params.leverSwap?.exactOutput?.abs()
34992
35006
  );
35007
+ logger.info(`VesuMultiplyAdapter::_getIncreaseCalldata amount: ${params.leverSwap?.exactOutput?.abs()}`);
34993
35008
  debtAmount = Web3Number.fromWei(swapQuote.total_calculated, debtToken.decimals).abs();
34994
35009
  }
35010
+ logger.info(`VesuMultiplyAdapter::_getIncreaseCalldata debtAmount: ${debtAmount}`);
34995
35011
  swapQuote = await ekuboQuoter.getQuoteExactInput(
34996
35012
  debtToken.address.address,
34997
35013
  collateralToken.address.address,
@@ -35018,7 +35034,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
35018
35034
  await new Promise((resolve) => setTimeout(resolve, 1e4));
35019
35035
  } else {
35020
35036
  throw new Error(
35021
- `VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
35037
+ `VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap, debtAmount=${debtAmount.toNumber()}, collateralPrice=${collateralPrice}, debtPrice=${debtPrice}`
35022
35038
  );
35023
35039
  }
35024
35040
  } catch (error) {
@@ -36003,6 +36019,9 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
36003
36019
  // src/strategies/universal-adapters/extended-adapter.ts
36004
36020
  var import_starknet27 = require("starknet");
36005
36021
 
36022
+ // src/modules/ExtendedWrapperSDk/wrapper.ts
36023
+ var import_bignumber6 = __toESM(require("bignumber.js"));
36024
+
36006
36025
  // src/modules/ExtendedWrapperSDk/types.ts
36007
36026
  var OrderSide = /* @__PURE__ */ ((OrderSide2) => {
36008
36027
  OrderSide2["BUY"] = "BUY";
@@ -36087,8 +36106,60 @@ var AssetOperationStatus = /* @__PURE__ */ ((AssetOperationStatus3) => {
36087
36106
  })(AssetOperationStatus || {});
36088
36107
 
36089
36108
  // src/modules/ExtendedWrapperSDk/wrapper.ts
36109
+ function asRecord(v) {
36110
+ return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
36111
+ }
36112
+ function pickTradingConfig(row) {
36113
+ const tc = row.trading_config ?? row.tradingConfig;
36114
+ return asRecord(tc);
36115
+ }
36116
+ function readTcString(tc, snake, camel) {
36117
+ const v = tc[snake] ?? tc[camel];
36118
+ if (v === void 0 || v === null) return void 0;
36119
+ return String(v).trim();
36120
+ }
36121
+ function tradingRulesFromMarketRow(marketName, row) {
36122
+ const r = asRecord(row);
36123
+ if (!r) {
36124
+ throw new Error(`ExtendedWrapper: invalid market payload for ${marketName}`);
36125
+ }
36126
+ const tc = pickTradingConfig(r);
36127
+ if (!tc) {
36128
+ throw new Error(`ExtendedWrapper: missing tradingConfig for market ${marketName}`);
36129
+ }
36130
+ const minS = readTcString(tc, "min_order_size", "minOrderSize");
36131
+ const qtyStep = readTcString(tc, "min_order_size_change", "minOrderSizeChange");
36132
+ const pxStep = readTcString(tc, "min_price_change", "minPriceChange");
36133
+ if (!minS || !qtyStep || !pxStep) {
36134
+ throw new Error(`ExtendedWrapper: incomplete tradingConfig for market ${marketName}`);
36135
+ }
36136
+ const minOrderSize = new import_bignumber6.default(minS);
36137
+ const qty = new import_bignumber6.default(qtyStep);
36138
+ const px = new import_bignumber6.default(pxStep);
36139
+ if (!minOrderSize.isFinite() || minOrderSize.lte(0)) {
36140
+ throw new Error(`ExtendedWrapper: invalid minOrderSize for ${marketName}`);
36141
+ }
36142
+ if (!qty.isFinite() || qty.lte(0)) {
36143
+ throw new Error(`ExtendedWrapper: invalid minOrderSizeChange for ${marketName}`);
36144
+ }
36145
+ if (!px.isFinite() || px.lte(0)) {
36146
+ throw new Error(`ExtendedWrapper: invalid minPriceChange for ${marketName}`);
36147
+ }
36148
+ return { minOrderSize, qtyStep: qty, priceStep: px };
36149
+ }
36150
+ function roundToStepBn(value, step) {
36151
+ if (step.lte(0)) return value;
36152
+ return value.div(step).round(0, import_bignumber6.default.ROUND_HALF_UP).times(step);
36153
+ }
36154
+ function formatBnForApi(bn, step) {
36155
+ const dp = Math.max(step.decimalPlaces() ?? 0, bn.decimalPlaces() ?? 0, 0);
36156
+ return Number(bn.toFixed(Math.min(80, dp))).toString();
36157
+ }
36090
36158
  var ExtendedWrapper = class {
36091
36159
  constructor(config) {
36160
+ /** Per-market rules from GET /markets (tradingConfig); retained for process lifetime (no TTL). */
36161
+ this.marketTradingRulesCache = /* @__PURE__ */ new Map();
36162
+ this.marketTradingRulesInflight = /* @__PURE__ */ new Map();
36092
36163
  this.apiKey = config.apiKey;
36093
36164
  this.timeout = config.timeout || 3e4;
36094
36165
  this.retries = config.retries || 3;
@@ -36152,13 +36223,75 @@ var ExtendedWrapper = class {
36152
36223
  }
36153
36224
  throw lastError || new Error("Request failed after all retries");
36154
36225
  }
36226
+ async resolveTradingRules(marketName) {
36227
+ const cached = this.marketTradingRulesCache.get(marketName);
36228
+ if (cached) return cached;
36229
+ const existing = this.marketTradingRulesInflight.get(marketName);
36230
+ if (existing) return existing;
36231
+ const inflight = (async () => {
36232
+ const res = await this.getMarkets(marketName);
36233
+ if (res.status !== "OK") {
36234
+ throw new Error(
36235
+ `ExtendedWrapper: getMarkets failed for ${marketName}: ${res.message}`
36236
+ );
36237
+ }
36238
+ const rows = res.data;
36239
+ if (!Array.isArray(rows) || rows.length === 0) {
36240
+ throw new Error(
36241
+ `ExtendedWrapper: empty markets response for ${marketName}`
36242
+ );
36243
+ }
36244
+ const row = rows.find((m) => asRecord(m)?.name === marketName);
36245
+ if (!row) {
36246
+ throw new Error(
36247
+ `ExtendedWrapper: market ${marketName} not found in markets list`
36248
+ );
36249
+ }
36250
+ const rules = tradingRulesFromMarketRow(marketName, row);
36251
+ this.marketTradingRulesCache.set(marketName, rules);
36252
+ return rules;
36253
+ })();
36254
+ this.marketTradingRulesInflight.set(marketName, inflight);
36255
+ void inflight.finally(() => {
36256
+ if (this.marketTradingRulesInflight.get(marketName) === inflight) {
36257
+ this.marketTradingRulesInflight.delete(marketName);
36258
+ }
36259
+ });
36260
+ return inflight;
36261
+ }
36155
36262
  /**
36156
36263
  * Create a new order on Extended Exchange
36157
36264
  */
36158
36265
  async createOrder(request) {
36266
+ const rules = await this.resolveTradingRules(request.market_name);
36267
+ const amountBn = new import_bignumber6.default(String(request.amount).trim());
36268
+ const priceBn = new import_bignumber6.default(String(request.price).trim());
36269
+ if (!amountBn.isFinite() || amountBn.lte(0)) {
36270
+ throw new Error(`ExtendedWrapper: invalid order amount=${request.amount}`);
36271
+ }
36272
+ if (!priceBn.isFinite() || priceBn.lte(0)) {
36273
+ throw new Error(`ExtendedWrapper: invalid order price=${request.price}`);
36274
+ }
36275
+ if (amountBn.lt(rules.minOrderSize)) {
36276
+ throw new Error(
36277
+ `ExtendedWrapper: order amount ${request.amount} is below minOrderSize ${rules.minOrderSize.toFixed()} for ${request.market_name}`
36278
+ );
36279
+ }
36280
+ const adjAmount = roundToStepBn(amountBn, rules.qtyStep);
36281
+ const adjPrice = roundToStepBn(priceBn, rules.priceStep);
36282
+ if (adjAmount.lt(rules.minOrderSize)) {
36283
+ throw new Error(
36284
+ `ExtendedWrapper: amount after tick rounding ${formatBnForApi(adjAmount, rules.qtyStep)} is below minOrderSize ${rules.minOrderSize.toFixed()} (${request.market_name})`
36285
+ );
36286
+ }
36287
+ const payload = {
36288
+ ...request,
36289
+ amount: formatBnForApi(adjAmount, rules.qtyStep),
36290
+ price: formatBnForApi(adjPrice, rules.priceStep)
36291
+ };
36159
36292
  return this.makeRequest("/api/v1/orders", false, {
36160
36293
  method: "POST",
36161
- body: JSON.stringify(request)
36294
+ body: JSON.stringify(payload)
36162
36295
  });
36163
36296
  }
36164
36297
  /**
@@ -36768,14 +36901,6 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
36768
36901
  logger.error("error initializing client");
36769
36902
  return null;
36770
36903
  }
36771
- const setLeverage = await this.setLeverage(
36772
- leverage,
36773
- this.config.extendedMarketName
36774
- );
36775
- if (!setLeverage) {
36776
- logger.error("error depositing or setting leverage");
36777
- return null;
36778
- }
36779
36904
  const { ask, bid } = await this.fetchOrderBookFromExtended();
36780
36905
  if (!ask || !bid || ask.lessThanOrEqualTo(0) || bid.lessThanOrEqualTo(0)) {
36781
36906
  logger.error(
@@ -36915,13 +37040,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
36915
37040
  async createExtendedPositon(client, marketName, amount, price, side) {
36916
37041
  try {
36917
37042
  const result = side === "SELL" /* SELL */ ? await client.createSellOrder(marketName, amount, price, {
36918
- postOnly: false,
36919
- reduceOnly: false,
36920
- timeInForce: "IOC" /* IOC */
37043
+ post_only: false,
37044
+ reduce_only: false,
37045
+ time_in_force: "IOC" /* IOC */
36921
37046
  }) : await client.createBuyOrder(marketName, amount, price, {
36922
- postOnly: false,
36923
- reduceOnly: true,
36924
- timeInForce: "IOC" /* IOC */
37047
+ post_only: false,
37048
+ reduce_only: true,
37049
+ time_in_force: "IOC" /* IOC */
36925
37050
  });
36926
37051
  if (result.data.id) {
36927
37052
  const position_id = result.data.id.toString();
@@ -42386,20 +42511,42 @@ function mergeDeltas(a, b) {
42386
42511
  dTransferVesuToExt: a.dTransferVesuToExt + b.dTransferVesuToExt
42387
42512
  };
42388
42513
  }
42389
- function drawFunds(need, keys, pool) {
42514
+ function routableDrawAmount(avail, need, minRoutable) {
42515
+ if (avail <= 0 || need <= 0) return 0;
42516
+ const raw = Math.min(avail, need);
42517
+ if (raw <= 0) return 0;
42518
+ if (minRoutable <= 0) return raw;
42519
+ return raw > minRoutable ? raw : 0;
42520
+ }
42521
+ function drawFunds(need, keys, pool, minRoutable) {
42390
42522
  const draws = {};
42391
42523
  let unmet = need;
42392
42524
  for (const k of keys) {
42393
42525
  if (unmet <= 0) break;
42394
42526
  const avail = pool[k];
42395
- if (avail <= 0) continue;
42396
- const take = Math.min(avail, unmet);
42527
+ const take = routableDrawAmount(avail, unmet, minRoutable);
42528
+ if (take <= 0) continue;
42397
42529
  draws[k] = take;
42398
42530
  pool[k] -= take;
42399
42531
  unmet -= take;
42400
42532
  }
42401
42533
  return { draws, filled: need - unmet, unmet };
42402
42534
  }
42535
+ function drawExtendedAggregated(need, pool, minRoutable) {
42536
+ const draws = {};
42537
+ if (need <= 0) return { draws, filled: 0, unmet: 0 };
42538
+ const totalCap = Math.max(0, pool.extAvlWithdraw) + Math.max(0, pool.extUpnl);
42539
+ const want = routableDrawAmount(totalCap, need, minRoutable);
42540
+ if (want <= 0) return { draws, filled: 0, unmet: need };
42541
+ const fromAvl = Math.min(Math.max(0, pool.extAvlWithdraw), want);
42542
+ pool.extAvlWithdraw -= fromAvl;
42543
+ const fromUpnl = Math.min(Math.max(0, pool.extUpnl), want - fromAvl);
42544
+ pool.extUpnl -= fromUpnl;
42545
+ if (fromAvl > 0) draws.extAvlWithdraw = fromAvl;
42546
+ if (fromUpnl > 0) draws.extUpnl = fromUpnl;
42547
+ const filled = fromAvl + fromUpnl;
42548
+ return { draws, filled, unmet: need - filled };
42549
+ }
42403
42550
  function sumKeys(draws, keys) {
42404
42551
  return keys.reduce((s, k) => s + (draws[k] ?? 0), 0);
42405
42552
  }
@@ -42410,33 +42557,39 @@ function applyDrawsToDeltas(d, draws, sign) {
42410
42557
  d.dExtAvlWithdraw += sign * (draws.extAvlWithdraw ?? 0);
42411
42558
  d.dExtUpnl += sign * (draws.extUpnl ?? 0);
42412
42559
  }
42413
- function fixExtMargin(ext, price, pool) {
42560
+ function fixExtMargin(ext, price, pool, config) {
42414
42561
  const d = emptyDeltas();
42415
42562
  const deficit = computeExtDeficit(ext, price);
42416
42563
  if (deficit <= 0) return { d, unmet: 0 };
42417
- const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
42564
+ const minR = config.minRoutableUsd ?? 0;
42565
+ const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool, minR);
42418
42566
  applyDrawsToDeltas(d, draws, -1);
42419
42567
  d.dExtAvlWithdraw += filled;
42420
42568
  const fromVesu = draws.vesuBorrowCapacity ?? 0;
42421
42569
  if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
42422
42570
  return { d, unmet };
42423
42571
  }
42424
- function fixVesuMargin(vesu, price, pool, hfBuffer) {
42572
+ function fixVesuMargin(vesu, price, pool, hfBuffer, config) {
42425
42573
  const d = emptyDeltas();
42426
42574
  const hf = computeVesuHF(vesu, price);
42427
42575
  if (hf >= vesu.targetHF - hfBuffer) return { d, unmet: 0 };
42428
42576
  const repayTokens = computeVesuDebtRepay(vesu, price);
42429
42577
  const repayUsd = repayTokens * vesu.debtPrice;
42430
- const { draws, filled, unmet } = drawFunds(repayUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
42431
- applyDrawsToDeltas(d, draws, -1);
42578
+ const minR = config.minRoutableUsd ?? 0;
42579
+ const rMain = drawFunds(repayUsd, ["vaUsd", "walletUsd"], pool, minR);
42580
+ applyDrawsToDeltas(d, rMain.draws, -1);
42581
+ const rExt = drawExtendedAggregated(rMain.unmet, pool, minR);
42582
+ applyDrawsToDeltas(d, rExt.draws, -1);
42583
+ const filled = rMain.filled + rExt.filled;
42584
+ const unmet = rExt.unmet;
42432
42585
  d.dVesuDebt -= filled / vesu.debtPrice;
42433
- const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
42586
+ const fromExt = sumKeys(rExt.draws, ["extAvlWithdraw", "extUpnl"]);
42434
42587
  if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
42435
42588
  return { d, unmet };
42436
42589
  }
42437
42590
  function phase1(ext, vesu, price, pool, config) {
42438
- const extResult = fixExtMargin(ext, price, pool);
42439
- const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer);
42591
+ const extResult = fixExtMargin(ext, price, pool, config);
42592
+ const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer, config);
42440
42593
  return {
42441
42594
  deltas: mergeDeltas(extResult.d, vesuResult.d),
42442
42595
  extDeficitRemaining: extResult.unmet,
@@ -42476,26 +42629,31 @@ function roundFinalPosition(extPos, vesuPos, rawF, precision) {
42476
42629
  }
42477
42630
  return Math.max(0, Math.min(fFromExt, fFromVesu));
42478
42631
  }
42479
- function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, precision) {
42632
+ function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, config) {
42480
42633
  const d = emptyDeltas();
42634
+ const precision = config.positionPrecision;
42635
+ const minR = config.minRoutableUsd ?? 0;
42481
42636
  const targetLTV = computeVesuTargetLTV(vesu);
42482
42637
  const imbalance = extPos - vesuPos;
42483
42638
  let fundedGrowthBtc = 0;
42484
42639
  if (!isNegligible(imbalance, precision)) {
42485
42640
  if (imbalance > 0) {
42486
42641
  const equityCostUsd = computeVesuGrowthCost(imbalance, vesu, price);
42487
- const { draws, filled } = drawFunds(equityCostUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
42488
- applyDrawsToDeltas(d, draws, -1);
42642
+ const rMain = drawFunds(equityCostUsd, ["vaUsd", "walletUsd"], pool, minR);
42643
+ applyDrawsToDeltas(d, rMain.draws, -1);
42644
+ const rExt = drawExtendedAggregated(rMain.unmet, pool, minR);
42645
+ applyDrawsToDeltas(d, rExt.draws, -1);
42646
+ const filled = rMain.filled + rExt.filled;
42489
42647
  const grownBtc = computeVesuGrowthFromEquity(filled, vesu, price);
42490
42648
  d.dVesuPosition += grownBtc;
42491
42649
  fundedGrowthBtc = grownBtc;
42492
42650
  d.dVesuDebt += computeVesuGrowthDebt(grownBtc, vesu, price);
42493
- const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
42651
+ const fromExt = sumKeys(rExt.draws, ["extAvlWithdraw", "extUpnl"]);
42494
42652
  if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
42495
42653
  } else {
42496
42654
  const absImbalance = -imbalance;
42497
42655
  const marginCostUsd = absImbalance * price / extLev;
42498
- const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
42656
+ const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool, minR);
42499
42657
  applyDrawsToDeltas(d, draws, -1);
42500
42658
  const grownBtc = filled * extLev / price;
42501
42659
  d.dExtPosition += grownBtc;
@@ -42536,6 +42694,7 @@ function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool,
42536
42694
  return d;
42537
42695
  }
42538
42696
  function rebalance(inputs) {
42697
+ logger.info(`ltv-imbalance-rebalance-math::rebalance inputs=${JSON.stringify(inputs)}`);
42539
42698
  const { ext, vesu, btcPrice, config } = inputs;
42540
42699
  const pool = { ...inputs.funding };
42541
42700
  const p1 = phase1(ext, vesu, btcPrice, pool, config);
@@ -42552,7 +42711,7 @@ function rebalance(inputs) {
42552
42711
  ext.leverage,
42553
42712
  btcPrice,
42554
42713
  pool,
42555
- config.positionPrecision
42714
+ config
42556
42715
  );
42557
42716
  return mergeDeltas(p1.deltas, p2);
42558
42717
  }
@@ -43133,15 +43292,15 @@ var SolveBudget = class {
43133
43292
  return this.vesuPoolStates[0];
43134
43293
  }
43135
43294
  // ── Derived getters (buffered where applicable) ─────────────────────
43136
- /** Buffered VA USD: strategy-asset slot + optional USDC slot. */
43295
+ /** Buffered VA USD: non-stable asset slot (if any) + USDC slot. */
43137
43296
  get vaUsd() {
43138
- return this.bufferedTokenUsd(this.vaultAssetBalance) + this.bufferedTokenUsd(this.vaultUsdcBalance);
43297
+ return this.bufferedTokenUsd(this.vaultUsdcBalance);
43139
43298
  }
43140
43299
  /** Buffered USD in VA strategy-asset bucket only. */
43141
43300
  get vaAssetUsd() {
43142
43301
  return this.bufferedTokenUsd(this.vaultAssetBalance);
43143
43302
  }
43144
- /** Buffered USD in VA USDC bucket (0 when asset === USDC). */
43303
+ /** Buffered USD in VA USDC bucket (includes full VA idle when asset === USDC). */
43145
43304
  get vaUsdcUsd() {
43146
43305
  return this.bufferedTokenUsd(this.vaultUsdcBalance);
43147
43306
  }
@@ -43223,9 +43382,13 @@ var SolveBudget = class {
43223
43382
  get vesuRebalanceFlags() {
43224
43383
  return this.shouldVesuRebalance;
43225
43384
  }
43226
- /** Raw USD in VA (USDC slot + asset slot); spend caps when executing transfers. */
43385
+ /** Raw USD in VA (USDC slot + non-stable asset slot when distinct); spend caps when executing transfers. */
43227
43386
  _vaRawUsd() {
43228
- return this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
43387
+ return this._rawTokenUsd(this.vaultUsdcBalance);
43388
+ }
43389
+ /** VA liquidity usable for repay / {@link spendVaRawUsd} (matches nominal balances after any {@link applyBuffer} scaling). */
43390
+ get vaRawUsd() {
43391
+ return this._vaRawUsd();
43229
43392
  }
43230
43393
  _walletRawUsd() {
43231
43394
  return this._rawTokenUsd(this.walletBalance);
@@ -43301,7 +43464,7 @@ var SolveBudget = class {
43301
43464
  rem -= fromUsdc;
43302
43465
  }
43303
43466
  if (rem > 0 && this.vaultAssetBalance) {
43304
- this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
43467
+ throw new Error(`Not implemented: spendVA with vaultAssetBalance`);
43305
43468
  }
43306
43469
  this._recomputeUnusedBalance();
43307
43470
  logger.debug(`SolveBudget::spendVA usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
@@ -43311,7 +43474,10 @@ var SolveBudget = class {
43311
43474
  * Spend nominal/raw USD from VA (e.g. Vesu repay, on-chain USDC). Does not apply the safety buffer to the cap.
43312
43475
  */
43313
43476
  spendVaRawUsd(rawUsdDesired) {
43314
- const capRaw = this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
43477
+ const capRaw = (
43478
+ // this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
43479
+ this._rawTokenUsd(this.vaultUsdcBalance)
43480
+ );
43315
43481
  const usedRaw = Math.min(capRaw, Math.max(0, rawUsdDesired));
43316
43482
  if (usedRaw <= CASE_THRESHOLD_USD) return 0;
43317
43483
  let rem = usedRaw;
@@ -43321,7 +43487,7 @@ var SolveBudget = class {
43321
43487
  rem -= fromUsdc;
43322
43488
  }
43323
43489
  if (rem > 0 && this.vaultAssetBalance) {
43324
- this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
43490
+ throw new Error(`Not implemented: spendVaRawUsd with vaultAssetBalance`);
43325
43491
  }
43326
43492
  this._recomputeUnusedBalance();
43327
43493
  logger.debug(`SolveBudget::spendVaRawUsd usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
@@ -43336,7 +43502,7 @@ var SolveBudget = class {
43336
43502
  if (this.vaultUsdcBalance) {
43337
43503
  this._addUsdToTokenBalance(this.vaultUsdcBalance, rawUsd);
43338
43504
  } else if (this.vaultAssetBalance) {
43339
- this._addUsdToTokenBalance(this.vaultAssetBalance, rawUsd);
43505
+ throw new Error(`Not implemented: addToVA with vaultAssetBalance`);
43340
43506
  }
43341
43507
  this._recomputeUnusedBalance();
43342
43508
  logger.debug(`SolveBudget::addToVA rawUsd=${rawUsd}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
@@ -43375,7 +43541,7 @@ var SolveBudget = class {
43375
43541
  if (isSpend) {
43376
43542
  const capRaw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
43377
43543
  const useRaw = Math.min(capRaw, desiredRaw);
43378
- if (useRaw <= CASE_THRESHOLD_USD) return 0;
43544
+ if (useRaw <= 0) return 0;
43379
43545
  rawDelta = -useRaw;
43380
43546
  } else {
43381
43547
  rawDelta = desiredRaw;
@@ -43395,7 +43561,7 @@ var SolveBudget = class {
43395
43561
  if (isSpend) {
43396
43562
  const capRaw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
43397
43563
  const useRaw = Math.min(capRaw, desiredRaw);
43398
- if (useRaw <= CASE_THRESHOLD_USD) return 0;
43564
+ if (useRaw <= 0) return 0;
43399
43565
  rawDelta = -useRaw;
43400
43566
  } else {
43401
43567
  rawDelta = desiredRaw;
@@ -43410,10 +43576,12 @@ var SolveBudget = class {
43410
43576
  return rawDelta;
43411
43577
  }
43412
43578
  spendExtAvailTrade(rawDesired) {
43413
- const used = this._updateExtAvailWithdraw(rawDesired, true);
43414
- const usedUpnl = this._updateExtAvailUpnl(rawDesired, true);
43415
- logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
43416
- return used + usedUpnl;
43579
+ const usedWd = this._updateExtAvailWithdraw(rawDesired, true);
43580
+ const tookWd = Math.abs(usedWd);
43581
+ const rem = rawDesired - tookWd;
43582
+ const usedUpnl = rem > 0 ? this._updateExtAvailUpnl(rem, true) : 0;
43583
+ logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${usedWd + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
43584
+ return usedWd + usedUpnl;
43417
43585
  }
43418
43586
  // simply reduces available amounts, but maintains equity and balance.
43419
43587
  spendExtAvailTradeToEquityOnly(rawDesired) {
@@ -43733,7 +43901,7 @@ var ExtendedSVKVesuStateManager = class {
43733
43901
  this._fetchExtendedPositions()
43734
43902
  ]);
43735
43903
  logger.verbose(
43736
- `${this._tag}::_refresh VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}${vaultUsdcBalance ? `, VA USDC=$${vaultUsdcBalance.usdValue.toFixed(2)}` : ""}, wallet=${walletBalance.usdValue}`
43904
+ `${this._tag}::_refresh ${vaultAssetBalance ? `VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}, ` : ""}VA USDC=${vaultUsdcBalance.usdValue.toFixed(2)}, wallet=${walletBalance.usdValue}`
43737
43905
  );
43738
43906
  const unusedBalance = this._computeUnusedBalances(
43739
43907
  vaultAssetBalance,
@@ -43758,23 +43926,28 @@ var ExtendedSVKVesuStateManager = class {
43758
43926
  },
43759
43927
  vesuPoolStates
43760
43928
  });
43929
+ this._budget.logStateSummary();
43761
43930
  const totalUnusedUsd = unusedBalance.reduce(
43762
43931
  (acc, b) => acc + b.usdValue,
43763
43932
  0
43764
43933
  );
43765
43934
  logger.info(
43766
- `${this._tag}::_refresh completed \u2014 unusedBalances: ${unusedBalance.length} tokens, totalUnusedUsd: ${totalUnusedUsd.toFixed(2)}, extendedPositions: ${extendedPositions.length}, vesuPools: ${vesuPoolStates.length} - availableForTrade: ${extendedBalance?.availableForTrade.toNumber()} - availableForWithdrawal: ${extendedBalance?.availableForWithdrawal.toNumber()} - unrealisedPnl: ${extendedBalance?.unrealisedPnl.toNumber()} - extendedBalance::balance: ${extendedBalance?.balance.toNumber()} - extendedBalance::pendingDeposit: ${extendedBalance?.pendingDeposit.toNumber()} - extendedBalance::equity: ${extendedBalance?.equity.toNumber()}`
43935
+ `${this._tag}::_refresh completed \u2014 unusedBalances: ${unusedBalance.length} tokens [${unusedBalance.map((b) => `${b.token.symbol}=$${b.usdValue.toFixed(2)}`).join(", ")}], totalUnusedUsd: ${totalUnusedUsd.toFixed(2)}, extendedPositions: ${extendedPositions.length} [${extendedPositions.map((p) => `${p.instrument}=${p.size.toFixed(6)} ${p.side}, ${p.valueUsd.toFixed(6)} ${p.instrument}`).join(", ")}], vesuPools: ${vesuPoolStates.length} [${vesuPoolStates.map((p) => `${p.poolId.shortString()}=${p.debtAmount.toFixed(6)} ${p.debtToken.symbol}, ${p.collateralAmount.toFixed(6)} ${p.collateralToken.symbol}`).join(", ")}], availableForTrade: ${extendedBalance?.availableForTrade.toNumber()} - availableForWithdrawal: ${extendedBalance?.availableForWithdrawal.toNumber()} - unrealisedPnl: ${extendedBalance?.unrealisedPnl.toNumber()} - extendedBalance::balance: ${extendedBalance?.balance.toNumber()} - extendedBalance::pendingDeposit: ${extendedBalance?.pendingDeposit.toNumber()} - extendedBalance::equity: ${extendedBalance?.equity.toNumber()}`
43767
43936
  );
43768
43937
  }
43769
43938
  // todo add communication check with python server of extended. if not working, throw error in solve function.
43770
- /** True when strategy asset and USDC share one token — VA USDC slot is unused (all in asset balance). */
43939
+ /** True when strategy asset and USDC share one token — VA idle balance is tracked as USDC, not as asset. */
43771
43940
  _vaultAssetAndUsdcAreSameToken() {
43772
43941
  return this._config.assetToken.address.eq(this._config.usdcToken.address);
43773
43942
  }
43774
43943
  /**
43775
- * Reads the {@link StateManagerConfig.assetToken} balance idle in the vault allocator.
43944
+ * Reads idle {@link StateManagerConfig.assetToken} in the vault allocator when it differs from USDC.
43945
+ * When asset and USDC are the same token, returns null (that balance is reported via {@link _fetchVaultAllocatorUsdcBalanceIfDistinct} only).
43776
43946
  */
43777
43947
  async _fetchVaultAllocatorAssetBalance() {
43948
+ if (this._vaultAssetAndUsdcAreSameToken()) {
43949
+ return null;
43950
+ }
43778
43951
  const { assetToken, vaultAllocator, networkConfig, pricer } = this._config;
43779
43952
  const balance = await new ERC20(networkConfig).balanceOf(
43780
43953
  assetToken.address,
@@ -43786,11 +43959,9 @@ var ExtendedSVKVesuStateManager = class {
43786
43959
  return { token: assetToken, amount: balance, usdValue };
43787
43960
  }
43788
43961
  /**
43789
- * Reads {@link StateManagerConfig.usdcToken} in the vault allocator when it differs from
43790
- * {@link StateManagerConfig.assetToken}. Otherwise returns null (treat VA USDC as 0; stablecoin is only under asset).
43962
+ * Reads {@link StateManagerConfig.usdcToken} idle in the vault allocator (always distinct asset or USDC-as-asset).
43791
43963
  */
43792
43964
  async _fetchVaultAllocatorUsdcBalanceIfDistinct() {
43793
- if (this._vaultAssetAndUsdcAreSameToken()) return null;
43794
43965
  const { usdcToken, vaultAllocator, networkConfig, pricer } = this._config;
43795
43966
  const balance = await new ERC20(networkConfig).balanceOf(
43796
43967
  usdcToken.address,
@@ -43804,7 +43975,7 @@ var ExtendedSVKVesuStateManager = class {
43804
43975
  return { token: usdcToken, amount: balance, usdValue };
43805
43976
  }
43806
43977
  /**
43807
- * Merges vault-allocator asset, optional vault-allocator USDC, and operator wallet
43978
+ * Merges vault-allocator asset (if any), vault-allocator USDC, and operator wallet
43808
43979
  * balances into entries keyed by token address.
43809
43980
  */
43810
43981
  _computeUnusedBalances(vaultAssetBalance, vaultUsdcBalance, walletBalance) {
@@ -43816,8 +43987,8 @@ var ExtendedSVKVesuStateManager = class {
43816
43987
  usdValue: tb.usdValue
43817
43988
  });
43818
43989
  };
43819
- put(vaultAssetBalance);
43820
- if (vaultUsdcBalance) put(vaultUsdcBalance);
43990
+ if (vaultAssetBalance) put(vaultAssetBalance);
43991
+ put(vaultUsdcBalance);
43821
43992
  const key = walletBalance.token.address.toString();
43822
43993
  const existing = balanceMap.get(key);
43823
43994
  if (existing) {
@@ -44336,7 +44507,10 @@ var ExtendedSVKVesuStateManager = class {
44336
44507
  // ── ExecutionRoute-building helpers ─────────────────────────────────────────────
44337
44508
  // ── Atomic route builders ────────────────────────────────────────────
44338
44509
  _buildVesuRepayRoutes(totalUsd, routes) {
44339
- const { used, spendsByPool } = this._budget.repayVesuBorrowCapacity(totalUsd);
44510
+ const vaCap = this._budget.vaRawUsd;
44511
+ const repayUsd = Math.min(totalUsd, vaCap);
44512
+ if (repayUsd <= CASE_THRESHOLD_USD) return;
44513
+ const { used, spendsByPool } = this._budget.repayVesuBorrowCapacity(repayUsd);
44340
44514
  for (const route of spendsByPool) {
44341
44515
  routes.push({ type: "VESU_REPAY" /* VESU_REPAY */, ...route, priority: routes.length });
44342
44516
  }
@@ -44430,7 +44604,7 @@ var ExtendedSVKVesuStateManager = class {
44430
44604
  return { routes, remaining: tryAmount };
44431
44605
  }
44432
44606
  _getVAToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
44433
- const usable = Math.min(tryAmount, this._budget.vaUsd);
44607
+ const usable = Math.min(tryAmount, this._budget.vaUsdcUsd);
44434
44608
  if (usable > CASE_THRESHOLD_USD) {
44435
44609
  const vaUsed = this._budget.spendVA(usable);
44436
44610
  this._budget.addToExtAvailTrade(vaUsed);
@@ -44445,7 +44619,7 @@ var ExtendedSVKVesuStateManager = class {
44445
44619
  }
44446
44620
  _getExtendedToWalletRoute(tryAmount, routes, shouldAddWaitRoute = true) {
44447
44621
  if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
44448
- const rawCap = this._budget.extAvailWithdraw + this._budget.extAvailUpnl;
44622
+ const rawCap = this._budget.extAvailWithdraw + Math.max(0, this._budget.extAvailUpnl);
44449
44623
  const rawSpend = Math.min(tryAmount, rawCap);
44450
44624
  if (rawSpend <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
44451
44625
  const rawOut = this._budget.spendExtAvailTrade(rawSpend);
@@ -44635,7 +44809,9 @@ var ExtendedSVKVesuStateManager = class {
44635
44809
  * Design: accumulate all ext-to-wallet moves, add transfer routes at the end (principle #3).
44636
44810
  */
44637
44811
  /**
44638
- * Unified LTV classifier. Computes both Vesu repay and Extended margin needs,
44812
+ * Unified LTV / exposure classifier: `rebalance()` drives both LTV (debt, margin,
44813
+ * funding) and Vesu↔Extended position alignment. There is no separate imbalance pass.
44814
+ * Computes both Vesu repay and Extended margin needs,
44639
44815
  * then builds all routes in a single pass with no duplicate transfers.
44640
44816
  *
44641
44817
  * Vesu repay priority: VA > Wallet > ExtAvl > ExtUpnl
@@ -44691,7 +44867,8 @@ var ExtendedSVKVesuStateManager = class {
44691
44867
  },
44692
44868
  config: {
44693
44869
  positionPrecision: COLLATERAL_PRECISION,
44694
- hfBuffer: 0.05
44870
+ hfBuffer: 0.05,
44871
+ minRoutableUsd: CASE_THRESHOLD_USD
44695
44872
  }
44696
44873
  };
44697
44874
  }
@@ -44702,8 +44879,9 @@ var ExtendedSVKVesuStateManager = class {
44702
44879
  }
44703
44880
  /**
44704
44881
  * Turn pure rebalance() deltas into execution routes.
44705
- * Order: Vesu multiply (decrease/increase) → Extended lever → aggregated transfers
44706
- * (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED).
44882
+ * Order: Vesu multiply decrease → Extended decrease → aggregated transfers
44883
+ * (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED),
44884
+ * then Vesu multiply increase and Extended increase (need VA / Extended funded first).
44707
44885
  */
44708
44886
  _buildLtvRoutesFromRebalanceDeltas(d) {
44709
44887
  const routes = [];
@@ -44715,6 +44893,7 @@ var ExtendedSVKVesuStateManager = class {
44715
44893
  const targetLtv = VesuConfig.targetLtv;
44716
44894
  const btcEps = 10 ** -COLLATERAL_PRECISION;
44717
44895
  let multiplyDebtRepayUsd = 0;
44896
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas d=${JSON.stringify(d)}`);
44718
44897
  if (d.dVesuPosition < -btcEps) {
44719
44898
  const xBtc = -d.dVesuPosition;
44720
44899
  const transferUsdFromVesu = Math.max(0, d.dTransferVesuToExt);
@@ -44733,12 +44912,28 @@ var ExtendedSVKVesuStateManager = class {
44733
44912
  if (d.dVesuDebt < 0) {
44734
44913
  const needRepayUsd = -d.dVesuDebt * debtPrice;
44735
44914
  const multiplyRepayUsd = Math.min(needRepayUsd, swapLegMaxRepayUsd);
44915
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas ${JSON.stringify({
44916
+ needRepayUsd,
44917
+ multiplyRepayUsd
44918
+ })}`);
44736
44919
  debtTokenDelta = -(multiplyRepayUsd / debtPrice);
44737
44920
  } else {
44738
44921
  debtTokenDelta = -debtUsdFallback;
44739
44922
  }
44740
44923
  const debtAmtW3 = new Web3Number(debtTokenDelta.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
44741
44924
  multiplyDebtRepayUsd = Math.abs(debtTokenDelta) * debtPrice;
44925
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas ${JSON.stringify({
44926
+ debtTokenDelta,
44927
+ debtUsdFallback,
44928
+ swapLegMaxRepayUsd,
44929
+ xBtc,
44930
+ marginBtc,
44931
+ swappedBtc,
44932
+ transferUsdFromVesu,
44933
+ debtPrice,
44934
+ targetLtv,
44935
+ multiplyDebtRepayUsd
44936
+ })}`);
44742
44937
  routes.push({
44743
44938
  type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
44744
44939
  poolId: vesuAdapter.config.poolId,
@@ -44759,19 +44954,68 @@ var ExtendedSVKVesuStateManager = class {
44759
44954
  if (transferUsdFromVesu > CASE_THRESHOLD_USD) {
44760
44955
  this._budget.addToVA(transferUsdFromVesu);
44761
44956
  }
44762
- } else if (d.dVesuPosition > btcEps) {
44957
+ }
44958
+ if (d.dExtPosition < -btcEps) {
44959
+ const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
44960
+ routes.push({
44961
+ type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
44962
+ amount: amt,
44963
+ instrument,
44964
+ priority: routes.length
44965
+ });
44966
+ this._budget.applyExtendedExposureDelta(instrument, amt, price);
44967
+ }
44968
+ const negUpnl = Math.min(0, d.dExtUpnl);
44969
+ const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
44970
+ let hadExtendedOut = false;
44971
+ if (negUpnl < -CASE_THRESHOLD_USD) {
44972
+ this._getUpnlRoute(Math.abs(negUpnl), routes);
44973
+ hadExtendedOut = true;
44974
+ }
44975
+ const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
44976
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas extToWalletUsd=${extToWalletUsd}, negExtAvl=${negExtAvl}, negUpnl=${negUpnl}`);
44977
+ if (extToWalletUsd > CASE_THRESHOLD_USD) {
44978
+ this._getExtendedToWalletRoute(extToWalletUsd, routes);
44979
+ hadExtendedOut = true;
44980
+ } else {
44981
+ if (d.dVesuDebt < 0) {
44982
+ d.dVesuDebt += (negExtAvl < 0 && negExtAvl > -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < 0 && negUpnl > -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
44983
+ }
44984
+ }
44985
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas d=${JSON.stringify(d)}`);
44986
+ const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
44987
+ const walletToVaUsd = walletPull + extToWalletUsd;
44988
+ if (walletToVaUsd > CASE_THRESHOLD_USD) {
44989
+ this._getWALLETToVARoute(walletToVaUsd, routes);
44990
+ }
44991
+ if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
44992
+ this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
44993
+ }
44994
+ const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
44995
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas totalDebtRepayUsd=${totalDebtRepayUsd}`);
44996
+ let standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
44997
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas standaloneRepayUsd=${standaloneRepayUsd}`);
44998
+ if (standaloneRepayUsd > this._budget.vaRawUsd) {
44999
+ if (Math.abs(standaloneRepayUsd - this._budget.vaRawUsd) < CASE_THRESHOLD_USD) {
45000
+ standaloneRepayUsd = this._budget.vaRawUsd;
45001
+ } else {
45002
+ throw new Error(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas standaloneRepayUsd=${standaloneRepayUsd} > vaRawUsd=${this._budget.vaRawUsd}`);
45003
+ }
45004
+ }
45005
+ if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
45006
+ this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
45007
+ }
45008
+ const posExtEq = Math.max(0, d.dExtAvlWithdraw);
45009
+ const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
45010
+ if (vaToExtUsd > CASE_THRESHOLD_USD) {
45011
+ this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
45012
+ }
45013
+ if (d.dVesuPosition > btcEps) {
44763
45014
  const vesuDepositAmount = new Web3Number(
44764
45015
  (d.dVesuPosition * price * (1 - targetLtv)).toFixed(USDC_TOKEN_DECIMALS),
44765
45016
  USDC_TOKEN_DECIMALS
44766
45017
  );
44767
45018
  if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
44768
- routes.push({
44769
- type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
44770
- priority: routes.length,
44771
- fromToken: vesuAdapter.config.collateral.symbol,
44772
- fromAmount: vesuDepositAmount,
44773
- toToken: vesuAdapter.config.debt.symbol
44774
- });
44775
45019
  }
44776
45020
  const collateralDelta = new Web3Number(
44777
45021
  d.dVesuPosition.toFixed(COLLATERAL_PRECISION),
@@ -44782,8 +45026,9 @@ var ExtendedSVKVesuStateManager = class {
44782
45026
  new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
44783
45027
  );
44784
45028
  const collPx = pool.collateralPrice || 1;
45029
+ const marginUsdAmount = externalDepositAmount.toNumber() * (pool.debtPrice ?? 1);
44785
45030
  const swappedAmount = new Web3Number(
44786
- (externalDepositAmount.toNumber() * (pool.debtPrice ?? 1) / collPx).toFixed(6),
45031
+ (marginUsdAmount / collPx).toFixed(6),
44787
45032
  vesuAdapter.config.collateral.decimals
44788
45033
  );
44789
45034
  const debtDeltaTokens = new Web3Number(
@@ -44807,17 +45052,9 @@ var ExtendedSVKVesuStateManager = class {
44807
45052
  collateralDelta,
44808
45053
  debtDeltaTokens
44809
45054
  );
45055
+ this._budget.spendVA(marginUsdAmount);
44810
45056
  }
44811
- if (d.dExtPosition < -btcEps) {
44812
- const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
44813
- routes.push({
44814
- type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
44815
- amount: amt,
44816
- instrument,
44817
- priority: routes.length
44818
- });
44819
- this._budget.applyExtendedExposureDelta(instrument, amt, price);
44820
- } else if (d.dExtPosition > btcEps) {
45057
+ if (d.dExtPosition > btcEps) {
44821
45058
  const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
44822
45059
  routes.push({
44823
45060
  type: "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
@@ -44827,36 +45064,6 @@ var ExtendedSVKVesuStateManager = class {
44827
45064
  });
44828
45065
  this._budget.applyExtendedExposureDelta(instrument, amt, price);
44829
45066
  }
44830
- const negUpnl = Math.min(0, d.dExtUpnl);
44831
- const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
44832
- let hadExtendedOut = false;
44833
- if (negUpnl < -CASE_THRESHOLD_USD) {
44834
- this._getUpnlRoute(Math.abs(negUpnl), routes);
44835
- hadExtendedOut = true;
44836
- }
44837
- const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
44838
- if (extToWalletUsd > CASE_THRESHOLD_USD) {
44839
- this._getExtendedToWalletRoute(extToWalletUsd, routes);
44840
- hadExtendedOut = true;
44841
- }
44842
- const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
44843
- const walletToVaUsd = walletPull + extToWalletUsd;
44844
- if (walletToVaUsd > CASE_THRESHOLD_USD) {
44845
- this._getWALLETToVARoute(walletToVaUsd, routes);
44846
- }
44847
- if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
44848
- this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
44849
- }
44850
- const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
44851
- const standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
44852
- if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
44853
- this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
44854
- }
44855
- const posExtEq = Math.max(0, d.dExtAvlWithdraw);
44856
- const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
44857
- if (vaToExtUsd > CASE_THRESHOLD_USD) {
44858
- this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
44859
- }
44860
45067
  return routes;
44861
45068
  }
44862
45069
  // ── LTV Vesu route builders ───────────────────────────────────────────
@@ -45015,48 +45222,76 @@ var ExtendedSVKVesuStateManager = class {
45015
45222
  const extendedTarget = total / (1 + extendedLeverage / vesuLeverage);
45016
45223
  const extendedInitial = extAvlWithdraw + extUpnl;
45017
45224
  let delta = extendedTarget - extendedInitial;
45018
- let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0;
45225
+ let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0, finalVaUsd = vaUsd, finalExtended = extAvlWithdraw + Math.max(extUpnl, 0);
45019
45226
  if (delta > 0) {
45020
45227
  let need = delta;
45021
- const takeWalletUsd = Math.min(walletUsd, need);
45228
+ const eps = CASE_THRESHOLD_USD;
45229
+ const takeWalletUsd = routableDrawAmount(walletUsd, need, eps);
45022
45230
  dWalletUsd -= takeWalletUsd;
45023
45231
  need -= takeWalletUsd;
45024
- const takeVaUsd = Math.min(vaUsd, need);
45232
+ const takeVaUsd = routableDrawAmount(vaUsd, need, eps);
45025
45233
  dVaUsd -= takeVaUsd;
45026
45234
  need -= takeVaUsd;
45027
- const takeVesuBorrowCapacity = Math.min(vesuBorrowCapacity, need);
45235
+ finalVaUsd -= takeVaUsd;
45236
+ finalVaUsd += walletUsd - takeWalletUsd;
45237
+ const takeVesuBorrowCapacity = routableDrawAmount(vesuBorrowCapacity, need, eps);
45028
45238
  dVesuBorrowCapacity -= takeVesuBorrowCapacity;
45029
45239
  need -= takeVesuBorrowCapacity;
45240
+ finalVaUsd += vesuBorrowCapacity - takeVesuBorrowCapacity;
45030
45241
  const received = delta - need;
45031
45242
  const eco1Sum = extAvlWithdraw + extUpnl;
45243
+ finalExtended += received;
45032
45244
  if (eco1Sum >= 0) {
45033
45245
  dExtAvlWithdraw += received;
45034
45246
  } else {
45035
- throw new Error(`${this._tag}: Unexpected case`);
45247
+ const hole = -eco1Sum;
45248
+ const fillUpnl = Math.min(received, hole);
45249
+ dExtUpnl += fillUpnl;
45250
+ dExtAvlWithdraw += received - fillUpnl;
45251
+ finalExtended -= fillUpnl;
45036
45252
  }
45037
- if (need > 0) {
45253
+ if (need > CASE_THRESHOLD_USD) {
45038
45254
  throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
45039
45255
  }
45040
45256
  } else if (delta < 0) {
45041
45257
  let need = -delta;
45042
- const takeExtAvlWithdraw = Math.min(extAvlWithdraw, need);
45258
+ const takeExtAvlWithdraw = Math.min(Math.max(extAvlWithdraw, 0), need);
45043
45259
  dExtAvlWithdraw -= takeExtAvlWithdraw;
45044
- need -= takeExtAvlWithdraw;
45045
- const takeExtUpnl = Math.min(extUpnl, need);
45260
+ const takeExtUpnl = Math.min(Math.max(extUpnl, 0), need);
45046
45261
  dExtUpnl -= takeExtUpnl;
45047
- need -= takeExtUpnl;
45262
+ const netDrawableAmount = takeExtAvlWithdraw + takeExtUpnl;
45263
+ if (netDrawableAmount > CASE_THRESHOLD_USD) {
45264
+ need -= netDrawableAmount;
45265
+ finalExtended -= netDrawableAmount;
45266
+ }
45048
45267
  const sent = -delta - need;
45049
45268
  const eco2Sum = vaUsd + walletUsd + vesuBorrowCapacity;
45269
+ const netWalletUsd = walletUsd < CASE_THRESHOLD_USD ? 0 : walletUsd;
45270
+ finalVaUsd += sent + netWalletUsd;
45050
45271
  if (eco2Sum >= 0) {
45051
45272
  dWalletUsd += sent;
45052
45273
  } else {
45053
45274
  throw new Error(`${this._tag}: Unexpected case`);
45054
45275
  }
45055
- if (need > 0) {
45276
+ if (need > CASE_THRESHOLD_USD) {
45056
45277
  throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
45057
45278
  }
45058
45279
  }
45059
- return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu: delta < 0 };
45280
+ return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, finalVaUsd, finalExtended, isExtendedToVesu: delta < 0 };
45281
+ }
45282
+ _scaleVesuPoolDeltasByFactor(deltas, scale) {
45283
+ if (scale >= 1 - 1e-15) return deltas;
45284
+ return deltas.map((d) => ({
45285
+ ...d,
45286
+ collateralDelta: new Web3Number(
45287
+ (d.collateralDelta.toNumber() * scale).toFixed(COLLATERAL_PRECISION),
45288
+ d.collateralToken.decimals
45289
+ ),
45290
+ debtDelta: new Web3Number(
45291
+ (d.debtDelta.toNumber() * scale).toFixed(USDC_TOKEN_DECIMALS),
45292
+ USDC_TOKEN_DECIMALS
45293
+ )
45294
+ }));
45060
45295
  }
45061
45296
  /**
45062
45297
  * 3. New Deposits / Excess Funds
@@ -45072,6 +45307,11 @@ var ExtendedSVKVesuStateManager = class {
45072
45307
  * Computes allocation split between Vesu and Extended, then sources
45073
45308
  * funds and creates lever-increase routes.
45074
45309
  *
45310
+ * Order: {@link _rebalanceFunds} first → project VA / Extended liquid after the same funding
45311
+ * routes (wallet→VA, borrow→VA, VA→Extended, Extended→wallet→VA) → ideal Vesu/Extended deltas
45312
+ * from distributable split → cap common BTC by min(Vesu fundable, Extended fundable) → scale
45313
+ * Vesu deltas and recompute Extended deltas so both sides stay matched.
45314
+ *
45075
45315
  * Fund flow (single pass — avoid VA→Extended then Extended→wallet round-trips):
45076
45316
  * 1) Treat Vesu borrow headroom that the multiply route will consume as covering
45077
45317
  * part of the Vesu USDC need (no standalone VESU_BORROW for that slice). Cap
@@ -45094,15 +45334,9 @@ var ExtendedSVKVesuStateManager = class {
45094
45334
  withdrawAmount
45095
45335
  );
45096
45336
  if (distributableAmount.toNumber() <= CASE_THRESHOLD_USD) return [];
45097
- const { vesuAllocationUsd, extendedAllocationUsd } = this._computeAllocationSplit(distributableAmount);
45098
- const vesuDeltas = this._computePerPoolCollateralDeltas(
45099
- vesuAllocationUsd
45100
- );
45101
- const extendedPositionDeltas = this._computeExtendedPositionDeltas(vesuDeltas);
45102
- const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
45103
45337
  const vesuLeverage = calculateVesuLeverage();
45104
45338
  const extendedLeverage = calculateExtendedLevergae();
45105
- const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu } = this._rebalanceFunds({
45339
+ const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu, finalVaUsd, finalExtended } = this._rebalanceFunds({
45106
45340
  extAvlWithdraw: this._budget.extAvailWithdraw,
45107
45341
  extUpnl: this._budget.extAvailUpnl,
45108
45342
  vaUsd: this._budget.vaUsd,
@@ -45111,6 +45345,23 @@ var ExtendedSVKVesuStateManager = class {
45111
45345
  vesuLeverage,
45112
45346
  extendedLeverage
45113
45347
  });
45348
+ logger.info(`${this._tag}::_classifyDeposits dExtAvlWithdraw=${dExtAvlWithdraw}, dExtUpnl=${dExtUpnl}, dVaUsd=${dVaUsd}, dWalletUsd=${dWalletUsd}, dVesuBorrowCapacity=${dVesuBorrowCapacity}, isExtendedToVesu=${isExtendedToVesu}, finalVaUsd=${finalVaUsd}`);
45349
+ let vesuDeltas = this._computePerPoolCollateralDeltas(new Web3Number(finalVaUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS));
45350
+ const collateralPrice = this._budget.vesuPools[0]?.collateralPrice ?? 0;
45351
+ const collateralDecimals = this._budget.vesuPools[0]?.collateralToken.decimals ?? 0;
45352
+ let _extendedPositionDelta = new Web3Number((finalExtended * extendedLeverage / collateralPrice).toFixed(USDC_TOKEN_DECIMALS), collateralDecimals).toFixedRoundDown(COLLATERAL_PRECISION);
45353
+ logger.info(`${this._tag}::_classifyDeposits extendedPositionDelta=${_extendedPositionDelta}`);
45354
+ logger.info(`${this._tag}::_classifyDeposits vesuDeltas=${JSON.stringify(vesuDeltas)}`);
45355
+ assert(vesuDeltas.length == 1, "vesuDeltas should have only one delta");
45356
+ const minPositionDelta = Math.min(vesuDeltas[0].collateralDelta.toNumber(), Number(_extendedPositionDelta));
45357
+ logger.info(`${this._tag}::_classifyDeposits minPositionDelta=${minPositionDelta}`);
45358
+ vesuDeltas[0].collateralDelta = new Web3Number(minPositionDelta.toFixed(COLLATERAL_PRECISION), vesuDeltas[0].collateralDelta.decimals);
45359
+ const extendedPositionDeltas = [{
45360
+ instrument: this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD",
45361
+ delta: new Web3Number(minPositionDelta.toFixed(COLLATERAL_PRECISION), collateralDecimals)
45362
+ }];
45363
+ const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
45364
+ logger.info(`${this._tag}::_classifyDeposits vesuDepositAmount=${vesuDepositAmount}`);
45114
45365
  const routes = [];
45115
45366
  if (isExtendedToVesu) {
45116
45367
  if (dExtUpnl < 0) {
@@ -45138,13 +45389,6 @@ var ExtendedSVKVesuStateManager = class {
45138
45389
  }
45139
45390
  for (const vesuDelta of vesuDeltas) {
45140
45391
  if (!skipAvnuDepositSwap && vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
45141
- routes.push({
45142
- type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
45143
- priority: routes.length,
45144
- fromToken: vesuDelta.collateralToken.symbol,
45145
- fromAmount: vesuDepositAmount,
45146
- toToken: vesuDelta.debtToken.symbol
45147
- });
45148
45392
  }
45149
45393
  if (vesuDelta.collateralDelta.toNumber() > 0) {
45150
45394
  const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
@@ -46124,14 +46368,6 @@ var _ExecutionService = class _ExecutionService {
46124
46368
  );
46125
46369
  return this._executeStandardCase(caseEntry, activeRoutes);
46126
46370
  }
46127
- const setLevResult = await this._config.extendedAdapter.setLeverage(calculateExtendedLevergae().toString(), this._config.extendedAdapter.config.extendedMarketName);
46128
- if (!setLevResult) {
46129
- logger.error(
46130
- `${this._tag}::_executeCoordinatedCase failed to set leverage`
46131
- );
46132
- results.push(this._failureResult(extendedRoute));
46133
- return results;
46134
- }
46135
46371
  const isIncrease = _ExecutionService.INCREASE_EXPOSURE_ROUTES.has(
46136
46372
  extendedRoute.type
46137
46373
  );
@@ -46152,8 +46388,9 @@ var _ExecutionService = class _ExecutionService {
46152
46388
  onChainCalls = callArrays.flat();
46153
46389
  } catch (err) {
46154
46390
  logger.error(
46155
- `${this._tag}::_executeCoordinatedCase on-chain call construction failed: ${err}`
46391
+ `${this._tag}::_executeCoordinatedCase on-chain call construction failed:`
46156
46392
  );
46393
+ console.error(err);
46157
46394
  await this._emitEvent("FAILURE" /* FAILURE */, {
46158
46395
  routeSummary: `coordinated on-chain build for case "${caseEntry.case.id}"`,
46159
46396
  error: `${err}`
@@ -46225,7 +46462,7 @@ var _ExecutionService = class _ExecutionService {
46225
46462
  }
46226
46463
  const timeoutMs = this._config.extendedFillTimeoutMs ?? DEFAULT_EXTENDED_FILL_TIMEOUT_MS;
46227
46464
  const extResult = await this._executeExtendedLimitOrderWithRecovery(
46228
- btcAmount,
46465
+ Math.abs(btcAmount),
46229
46466
  executionPrice,
46230
46467
  side,
46231
46468
  {
@@ -46753,7 +46990,7 @@ var _ExecutionService = class _ExecutionService {
46753
46990
  return this._failureResult(route);
46754
46991
  }
46755
46992
  const closeResult = await this._executeExtendedLimitOrderWithRecovery(
46756
- positionToClose.toNumber(),
46993
+ Math.abs(positionToClose.toNumber()),
46757
46994
  midPrice,
46758
46995
  "BUY" /* BUY */
46759
46996
  );
@@ -46771,7 +47008,7 @@ var _ExecutionService = class _ExecutionService {
46771
47008
  `${this._tag}::_executeRealisePnl reopening ${positionToClose.toNumber()} on ${route.instrument}`
46772
47009
  );
46773
47010
  const reopenResult = await this._executeExtendedLimitOrderWithRecovery(
46774
- positionToClose.toNumber(),
47011
+ Math.abs(positionToClose.toNumber()),
46775
47012
  midPrice,
46776
47013
  "SELL" /* SELL */
46777
47014
  );
@@ -46825,7 +47062,7 @@ var _ExecutionService = class _ExecutionService {
46825
47062
  return this._failureResult(route);
46826
47063
  }
46827
47064
  const result = await this._executeExtendedLimitOrderWithRecovery(
46828
- route.amount.toNumber(),
47065
+ Math.abs(route.amount.toNumber()),
46829
47066
  midPrice,
46830
47067
  "SELL" /* SELL */
46831
47068
  );
@@ -46873,7 +47110,7 @@ var _ExecutionService = class _ExecutionService {
46873
47110
  return this._failureResult(route);
46874
47111
  }
46875
47112
  const result = await this._executeExtendedLimitOrderWithRecovery(
46876
- route.amount.toNumber(),
47113
+ Math.abs(route.amount.toNumber()),
46877
47114
  midPrice,
46878
47115
  "BUY" /* BUY */
46879
47116
  );
@@ -47496,16 +47733,16 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
47496
47733
  ];
47497
47734
  }
47498
47735
  };
47499
- function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47736
+ function getLooperSettings3(collateralSymbol, underlyingSymbol, vaultSettings, pool1, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47500
47737
  vaultSettings.leafAdapters = [];
47501
47738
  const wbtcToken = Global.getDefaultTokens().find(
47502
- (token) => token.symbol === lstSymbol
47739
+ (token) => token.symbol === collateralSymbol
47503
47740
  );
47504
47741
  const usdcToken = Global.getDefaultTokens().find(
47505
47742
  (token) => token.symbol === underlyingSymbol
47506
47743
  );
47507
47744
  const baseAdapterConfig = {
47508
- baseToken: wbtcToken,
47745
+ baseToken: usdcToken,
47509
47746
  supportedPositions: [
47510
47747
  { asset: usdcToken, isDebt: true },
47511
47748
  { asset: wbtcToken, isDebt: false }
@@ -47605,7 +47842,7 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
47605
47842
  vaultAddress: vaultSettings.vaultAddress,
47606
47843
  vaultAllocator: vaultSettings.vaultAllocator,
47607
47844
  manager: vaultSettings.manager,
47608
- asset: wbtcToken.address
47845
+ asset: usdcToken.address
47609
47846
  });
47610
47847
  vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getDepositLeaf());
47611
47848
  vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getWithdrawLeaf());
@@ -47739,6 +47976,39 @@ var re7UsdcPrimeDevansh = {
47739
47976
  minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
47740
47977
  walletAddress: "0x024b563C1C7d41B32BF4EFB9F38828508a65Be2d6e25268E9f63F22C5e9E51c5"
47741
47978
  };
47979
+ var pureUsdc = {
47980
+ vaultAddress: ContractAddr.from(
47981
+ "0x745c972db65bdee10022fd875dd328c7f40a90849135b6a0f875a40f3c632ae"
47982
+ ),
47983
+ manager: ContractAddr.from(
47984
+ "0x364e0894edefb616ec090f57f5c0274517fcd98ab276ae1f021c5e962fa1deb"
47985
+ ),
47986
+ vaultAllocator: ContractAddr.from(
47987
+ "0x6fceed28e03a96091877568893df0dd89b9bb80fec30da2b742dacbd5526179"
47988
+ ),
47989
+ redeemRequestNFT: ContractAddr.from(
47990
+ "0x501c2b87728e22c6dfcebe4c0b2b3a9fba5845606e4d59fa7bf591badcbb42"
47991
+ ),
47992
+ aumOracle: ContractAddr.from(
47993
+ "0x6ccd95f5765242695d3c75e1440b1d0b30efac8babb864ce15729977b97cb82"
47994
+ ),
47995
+ leafAdapters: [],
47996
+ adapters: [],
47997
+ targetHealthFactor: 1.4,
47998
+ minHealthFactor: 1.35,
47999
+ underlyingToken: Global.getDefaultTokens().find(
48000
+ (token) => token.symbol === "USDC"
48001
+ ),
48002
+ quoteAmountToFetchPrice: new Web3Number(
48003
+ "0.001",
48004
+ Global.getDefaultTokens().find((token) => token.symbol === "USDC").decimals
48005
+ ),
48006
+ borrowable_assets: [
48007
+ Global.getDefaultTokens().find((token) => token.symbol === "USDC")
48008
+ ],
48009
+ minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
48010
+ walletAddress: "0x058571C23da5FEdd4e36003FAE3fE2fA9782f2692E552f081839142B10770D0B"
48011
+ };
47742
48012
  var VesuExtendedTestStrategies = (extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) => {
47743
48013
  return [
47744
48014
  getStrategySettingsVesuExtended(
@@ -47755,14 +48025,29 @@ var VesuExtendedTestStrategies = (extendedBackendReadUrl, extendedBackendWriteUr
47755
48025
  minimumExtendedRetriesDelayForOrderStatus,
47756
48026
  minimumExtendedPriceDifferenceForSwapOpen,
47757
48027
  maximumExtendedPriceDifferenceForSwapClosing
48028
+ ),
48029
+ getStrategySettingsVesuExtended(
48030
+ "WBTC",
48031
+ "USDC",
48032
+ pureUsdc,
48033
+ false,
48034
+ false,
48035
+ extendedBackendReadUrl,
48036
+ extendedBackendWriteUrl,
48037
+ vaultIdExtended,
48038
+ minimumExtendedMovementAmount,
48039
+ minimumVesuMovementAmount,
48040
+ minimumExtendedRetriesDelayForOrderStatus,
48041
+ minimumExtendedPriceDifferenceForSwapOpen,
48042
+ maximumExtendedPriceDifferenceForSwapClosing
47758
48043
  )
47759
48044
  ];
47760
48045
  };
47761
- function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses, isPreview = false, isLST, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
48046
+ function getStrategySettingsVesuExtended(collateralSymbol, underlyingSymbol, addresses, isPreview = false, isLST, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47762
48047
  return {
47763
48048
  id: `extended_${underlyingSymbol.toLowerCase()}_test`,
47764
48049
  name: `Extended Test ${underlyingSymbol}`,
47765
- description: getDescription3(lstSymbol, underlyingSymbol),
48050
+ description: getDescription3(collateralSymbol, underlyingSymbol),
47766
48051
  address: addresses.vaultAddress,
47767
48052
  launchBlock: 0,
47768
48053
  type: "Other",
@@ -47776,7 +48061,7 @@ function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses,
47776
48061
  )
47777
48062
  ],
47778
48063
  additionalInfo: getLooperSettings3(
47779
- lstSymbol,
48064
+ collateralSymbol,
47780
48065
  underlyingSymbol,
47781
48066
  addresses,
47782
48067
  VesuPools.Re7USDCPrime,
@@ -47797,8 +48082,8 @@ function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses,
47797
48082
  auditUrl: AUDIT_URL4,
47798
48083
  protocols: [Protocols.ENDUR, Protocols.VESU],
47799
48084
  contractDetails: getContractDetails(addresses),
47800
- faqs: getFAQs2(lstSymbol, underlyingSymbol, isLST),
47801
- investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
48085
+ faqs: getFAQs2(collateralSymbol, underlyingSymbol, isLST),
48086
+ investmentSteps: getInvestmentSteps(collateralSymbol, underlyingSymbol),
47802
48087
  isPreview,
47803
48088
  apyMethodology: isLST ? "Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown." : "Current annualized APY in terms of base asset of the Yield Token. There is no additional fee taken by Troves on yield token APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.",
47804
48089
  security: {