@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.mjs CHANGED
@@ -6013,7 +6013,7 @@ var EkuboQuoter = class _EkuboQuoter {
6013
6013
  async _callQuoterApi(fromToken, toToken, amount, retry = 0) {
6014
6014
  try {
6015
6015
  const url = this.ENDPOINT.replace("{{AMOUNT}}", amount.toWei()).replace("{{TOKEN_FROM_ADDRESS}}", fromToken).replace("{{TOKEN_TO_ADDRESS}}", toToken);
6016
- logger.verbose(`EkuboQuoter::_callQuoterApi url: ${url}`);
6016
+ logger.info(`EkuboQuoter::_callQuoterApi url: ${url}`);
6017
6017
  const quote = await axios6.get(url);
6018
6018
  return quote.data;
6019
6019
  } catch (error) {
@@ -7883,6 +7883,7 @@ var vesu_rebalance_abi_default = [
7883
7883
  var CacheClass = class {
7884
7884
  constructor() {
7885
7885
  this.cache = /* @__PURE__ */ new Map();
7886
+ this.isCacheEnabled = true;
7886
7887
  }
7887
7888
  setCache(key, data, ttl = 6e4) {
7888
7889
  const timestamp = Date.now();
@@ -7890,7 +7891,7 @@ var CacheClass = class {
7890
7891
  }
7891
7892
  getCache(key) {
7892
7893
  const cachedData = this.cache.get(key);
7893
- if (!cachedData || !this.isCacheValid(key)) {
7894
+ if (!cachedData || !this.isCacheValid(key) || !this.isCacheEnabled) {
7894
7895
  return null;
7895
7896
  }
7896
7897
  return cachedData.data;
@@ -7901,6 +7902,12 @@ var CacheClass = class {
7901
7902
  const { timestamp, ttl } = cachedData;
7902
7903
  return Date.now() - timestamp <= ttl;
7903
7904
  }
7905
+ disableCache() {
7906
+ this.isCacheEnabled = false;
7907
+ }
7908
+ enableCache() {
7909
+ this.isCacheEnabled = true;
7910
+ }
7904
7911
  };
7905
7912
 
7906
7913
  // src/strategies/base-strategy.ts
@@ -28691,7 +28698,7 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
28691
28698
  throw new Error("LTV is 0");
28692
28699
  }
28693
28700
  this.setCache(CACHE_KEY, ltv, 3e5);
28694
- return this.getCache(CACHE_KEY);
28701
+ return ltv;
28695
28702
  }
28696
28703
  async getPositions(config, blockNumber = "latest") {
28697
28704
  if (!this.pricer) {
@@ -28775,6 +28782,9 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
28775
28782
  debtPrice = (await pricer.getPrice(this.config.debt.priceProxySymbol || this.config.debt.symbol)).price;
28776
28783
  }
28777
28784
  logger.verbose(`VesuAdapter::getAssetPrices collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
28785
+ if (isNaN(collateralPrice) || isNaN(debtPrice) || collateralPrice == 0 || debtPrice == 0) {
28786
+ throw new Error(`VesuAdapter::getAssetPrices collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
28787
+ }
28778
28788
  return {
28779
28789
  collateralTokenAmount,
28780
28790
  collateralUSDAmount,
@@ -34413,20 +34423,23 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34413
34423
  }
34414
34424
  _buildZeroAmountSwapsWithWeights(quote, token, reverseRoutes = false) {
34415
34425
  const swaps = quote.splits.map((split) => {
34416
- const routeNodes = split.route.map((_route) => ({
34417
- pool_key: {
34418
- token0: ContractAddr.from(_route.pool_key.token0),
34419
- token1: ContractAddr.from(_route.pool_key.token1),
34420
- fee: _route.pool_key.fee,
34421
- tick_spacing: _route.pool_key.tick_spacing.toString(),
34422
- extension: _route.pool_key.extension
34423
- },
34424
- sqrt_ratio_limit: Web3Number.fromWei(_route.sqrt_ratio_limit, 18),
34425
- skip_ahead: Web3Number.fromWei(_route.skip_ahead, 0)
34426
- }));
34427
- if (reverseRoutes) {
34428
- routeNodes.reverse();
34429
- }
34426
+ let sellToken = token.address;
34427
+ const routeNodes = split.route.map((_route) => {
34428
+ let isSellToken0 = sellToken.eqString(_route.pool_key.token0);
34429
+ isSellToken0 = reverseRoutes ? !isSellToken0 : isSellToken0;
34430
+ sellToken = isSellToken0 ? ContractAddr.from(_route.pool_key.token1) : ContractAddr.from(_route.pool_key.token0);
34431
+ return {
34432
+ pool_key: {
34433
+ token0: ContractAddr.from(_route.pool_key.token0),
34434
+ token1: ContractAddr.from(_route.pool_key.token1),
34435
+ fee: _route.pool_key.fee,
34436
+ tick_spacing: _route.pool_key.tick_spacing.toString(),
34437
+ extension: _route.pool_key.extension
34438
+ },
34439
+ sqrt_ratio_limit: isSellToken0 ? Web3Number.fromWei(MIN_SQRT_RATIO_LIMIT.toString(), 18) : Web3Number.fromWei(MAX_SQRT_RATIO_LIMIT.toString(), 18),
34440
+ skip_ahead: Web3Number.fromWei(_route.skip_ahead, 0)
34441
+ };
34442
+ });
34430
34443
  return {
34431
34444
  route: routeNodes,
34432
34445
  token_amount: {
@@ -34748,6 +34761,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34748
34761
  collateralToken.address.address,
34749
34762
  requiredAmount
34750
34763
  );
34764
+ logger.info(`VesuMultiplyAdapter::_getIncreaseCalldata requiredAmount: ${requiredAmount}`);
34751
34765
  if (marginSwapQuote.price_impact > 0.01) {
34752
34766
  throw new Error(
34753
34767
  `VesuMultiplyAdapter: Margin swap price impact too high (${marginSwapQuote.price_impact})`
@@ -34774,7 +34788,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34774
34788
  legLTV,
34775
34789
  dexPrice
34776
34790
  );
34777
- logger.verbose(
34791
+ logger.info(
34778
34792
  `${_VesuMultiplyAdapter.name}::_getIncreaseCalldata debtAmount: ${debtAmount}, addedCollateral: ${addedCollateral}`
34779
34793
  );
34780
34794
  let leverSwap = [];
@@ -34792,8 +34806,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34792
34806
  collateralToken.address.address,
34793
34807
  params.leverSwap?.exactOutput?.abs()
34794
34808
  );
34809
+ logger.info(`VesuMultiplyAdapter::_getIncreaseCalldata amount: ${params.leverSwap?.exactOutput?.abs()}`);
34795
34810
  debtAmount = Web3Number.fromWei(swapQuote.total_calculated, debtToken.decimals).abs();
34796
34811
  }
34812
+ logger.info(`VesuMultiplyAdapter::_getIncreaseCalldata debtAmount: ${debtAmount}`);
34797
34813
  swapQuote = await ekuboQuoter.getQuoteExactInput(
34798
34814
  debtToken.address.address,
34799
34815
  collateralToken.address.address,
@@ -34820,7 +34836,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
34820
34836
  await new Promise((resolve) => setTimeout(resolve, 1e4));
34821
34837
  } else {
34822
34838
  throw new Error(
34823
- `VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
34839
+ `VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap, debtAmount=${debtAmount.toNumber()}, collateralPrice=${collateralPrice}, debtPrice=${debtPrice}`
34824
34840
  );
34825
34841
  }
34826
34842
  } catch (error) {
@@ -35805,6 +35821,9 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
35805
35821
  // src/strategies/universal-adapters/extended-adapter.ts
35806
35822
  import { hash as hash8, uint256 as uint25616 } from "starknet";
35807
35823
 
35824
+ // src/modules/ExtendedWrapperSDk/wrapper.ts
35825
+ import BigNumber3 from "bignumber.js";
35826
+
35808
35827
  // src/modules/ExtendedWrapperSDk/types.ts
35809
35828
  var OrderSide = /* @__PURE__ */ ((OrderSide2) => {
35810
35829
  OrderSide2["BUY"] = "BUY";
@@ -35889,8 +35908,60 @@ var AssetOperationStatus = /* @__PURE__ */ ((AssetOperationStatus3) => {
35889
35908
  })(AssetOperationStatus || {});
35890
35909
 
35891
35910
  // src/modules/ExtendedWrapperSDk/wrapper.ts
35911
+ function asRecord(v) {
35912
+ return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
35913
+ }
35914
+ function pickTradingConfig(row) {
35915
+ const tc = row.trading_config ?? row.tradingConfig;
35916
+ return asRecord(tc);
35917
+ }
35918
+ function readTcString(tc, snake, camel) {
35919
+ const v = tc[snake] ?? tc[camel];
35920
+ if (v === void 0 || v === null) return void 0;
35921
+ return String(v).trim();
35922
+ }
35923
+ function tradingRulesFromMarketRow(marketName, row) {
35924
+ const r = asRecord(row);
35925
+ if (!r) {
35926
+ throw new Error(`ExtendedWrapper: invalid market payload for ${marketName}`);
35927
+ }
35928
+ const tc = pickTradingConfig(r);
35929
+ if (!tc) {
35930
+ throw new Error(`ExtendedWrapper: missing tradingConfig for market ${marketName}`);
35931
+ }
35932
+ const minS = readTcString(tc, "min_order_size", "minOrderSize");
35933
+ const qtyStep = readTcString(tc, "min_order_size_change", "minOrderSizeChange");
35934
+ const pxStep = readTcString(tc, "min_price_change", "minPriceChange");
35935
+ if (!minS || !qtyStep || !pxStep) {
35936
+ throw new Error(`ExtendedWrapper: incomplete tradingConfig for market ${marketName}`);
35937
+ }
35938
+ const minOrderSize = new BigNumber3(minS);
35939
+ const qty = new BigNumber3(qtyStep);
35940
+ const px = new BigNumber3(pxStep);
35941
+ if (!minOrderSize.isFinite() || minOrderSize.lte(0)) {
35942
+ throw new Error(`ExtendedWrapper: invalid minOrderSize for ${marketName}`);
35943
+ }
35944
+ if (!qty.isFinite() || qty.lte(0)) {
35945
+ throw new Error(`ExtendedWrapper: invalid minOrderSizeChange for ${marketName}`);
35946
+ }
35947
+ if (!px.isFinite() || px.lte(0)) {
35948
+ throw new Error(`ExtendedWrapper: invalid minPriceChange for ${marketName}`);
35949
+ }
35950
+ return { minOrderSize, qtyStep: qty, priceStep: px };
35951
+ }
35952
+ function roundToStepBn(value, step) {
35953
+ if (step.lte(0)) return value;
35954
+ return value.div(step).round(0, BigNumber3.ROUND_HALF_UP).times(step);
35955
+ }
35956
+ function formatBnForApi(bn, step) {
35957
+ const dp = Math.max(step.decimalPlaces() ?? 0, bn.decimalPlaces() ?? 0, 0);
35958
+ return Number(bn.toFixed(Math.min(80, dp))).toString();
35959
+ }
35892
35960
  var ExtendedWrapper = class {
35893
35961
  constructor(config) {
35962
+ /** Per-market rules from GET /markets (tradingConfig); retained for process lifetime (no TTL). */
35963
+ this.marketTradingRulesCache = /* @__PURE__ */ new Map();
35964
+ this.marketTradingRulesInflight = /* @__PURE__ */ new Map();
35894
35965
  this.apiKey = config.apiKey;
35895
35966
  this.timeout = config.timeout || 3e4;
35896
35967
  this.retries = config.retries || 3;
@@ -35954,13 +36025,75 @@ var ExtendedWrapper = class {
35954
36025
  }
35955
36026
  throw lastError || new Error("Request failed after all retries");
35956
36027
  }
36028
+ async resolveTradingRules(marketName) {
36029
+ const cached = this.marketTradingRulesCache.get(marketName);
36030
+ if (cached) return cached;
36031
+ const existing = this.marketTradingRulesInflight.get(marketName);
36032
+ if (existing) return existing;
36033
+ const inflight = (async () => {
36034
+ const res = await this.getMarkets(marketName);
36035
+ if (res.status !== "OK") {
36036
+ throw new Error(
36037
+ `ExtendedWrapper: getMarkets failed for ${marketName}: ${res.message}`
36038
+ );
36039
+ }
36040
+ const rows = res.data;
36041
+ if (!Array.isArray(rows) || rows.length === 0) {
36042
+ throw new Error(
36043
+ `ExtendedWrapper: empty markets response for ${marketName}`
36044
+ );
36045
+ }
36046
+ const row = rows.find((m) => asRecord(m)?.name === marketName);
36047
+ if (!row) {
36048
+ throw new Error(
36049
+ `ExtendedWrapper: market ${marketName} not found in markets list`
36050
+ );
36051
+ }
36052
+ const rules = tradingRulesFromMarketRow(marketName, row);
36053
+ this.marketTradingRulesCache.set(marketName, rules);
36054
+ return rules;
36055
+ })();
36056
+ this.marketTradingRulesInflight.set(marketName, inflight);
36057
+ void inflight.finally(() => {
36058
+ if (this.marketTradingRulesInflight.get(marketName) === inflight) {
36059
+ this.marketTradingRulesInflight.delete(marketName);
36060
+ }
36061
+ });
36062
+ return inflight;
36063
+ }
35957
36064
  /**
35958
36065
  * Create a new order on Extended Exchange
35959
36066
  */
35960
36067
  async createOrder(request) {
36068
+ const rules = await this.resolveTradingRules(request.market_name);
36069
+ const amountBn = new BigNumber3(String(request.amount).trim());
36070
+ const priceBn = new BigNumber3(String(request.price).trim());
36071
+ if (!amountBn.isFinite() || amountBn.lte(0)) {
36072
+ throw new Error(`ExtendedWrapper: invalid order amount=${request.amount}`);
36073
+ }
36074
+ if (!priceBn.isFinite() || priceBn.lte(0)) {
36075
+ throw new Error(`ExtendedWrapper: invalid order price=${request.price}`);
36076
+ }
36077
+ if (amountBn.lt(rules.minOrderSize)) {
36078
+ throw new Error(
36079
+ `ExtendedWrapper: order amount ${request.amount} is below minOrderSize ${rules.minOrderSize.toFixed()} for ${request.market_name}`
36080
+ );
36081
+ }
36082
+ const adjAmount = roundToStepBn(amountBn, rules.qtyStep);
36083
+ const adjPrice = roundToStepBn(priceBn, rules.priceStep);
36084
+ if (adjAmount.lt(rules.minOrderSize)) {
36085
+ throw new Error(
36086
+ `ExtendedWrapper: amount after tick rounding ${formatBnForApi(adjAmount, rules.qtyStep)} is below minOrderSize ${rules.minOrderSize.toFixed()} (${request.market_name})`
36087
+ );
36088
+ }
36089
+ const payload = {
36090
+ ...request,
36091
+ amount: formatBnForApi(adjAmount, rules.qtyStep),
36092
+ price: formatBnForApi(adjPrice, rules.priceStep)
36093
+ };
35961
36094
  return this.makeRequest("/api/v1/orders", false, {
35962
36095
  method: "POST",
35963
- body: JSON.stringify(request)
36096
+ body: JSON.stringify(payload)
35964
36097
  });
35965
36098
  }
35966
36099
  /**
@@ -36570,14 +36703,6 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
36570
36703
  logger.error("error initializing client");
36571
36704
  return null;
36572
36705
  }
36573
- const setLeverage = await this.setLeverage(
36574
- leverage,
36575
- this.config.extendedMarketName
36576
- );
36577
- if (!setLeverage) {
36578
- logger.error("error depositing or setting leverage");
36579
- return null;
36580
- }
36581
36706
  const { ask, bid } = await this.fetchOrderBookFromExtended();
36582
36707
  if (!ask || !bid || ask.lessThanOrEqualTo(0) || bid.lessThanOrEqualTo(0)) {
36583
36708
  logger.error(
@@ -36717,13 +36842,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
36717
36842
  async createExtendedPositon(client, marketName, amount, price, side) {
36718
36843
  try {
36719
36844
  const result = side === "SELL" /* SELL */ ? await client.createSellOrder(marketName, amount, price, {
36720
- postOnly: false,
36721
- reduceOnly: false,
36722
- timeInForce: "IOC" /* IOC */
36845
+ post_only: false,
36846
+ reduce_only: false,
36847
+ time_in_force: "IOC" /* IOC */
36723
36848
  }) : await client.createBuyOrder(marketName, amount, price, {
36724
- postOnly: false,
36725
- reduceOnly: true,
36726
- timeInForce: "IOC" /* IOC */
36849
+ post_only: false,
36850
+ reduce_only: true,
36851
+ time_in_force: "IOC" /* IOC */
36727
36852
  });
36728
36853
  if (result.data.id) {
36729
36854
  const position_id = result.data.id.toString();
@@ -42188,20 +42313,42 @@ function mergeDeltas(a, b) {
42188
42313
  dTransferVesuToExt: a.dTransferVesuToExt + b.dTransferVesuToExt
42189
42314
  };
42190
42315
  }
42191
- function drawFunds(need, keys, pool) {
42316
+ function routableDrawAmount(avail, need, minRoutable) {
42317
+ if (avail <= 0 || need <= 0) return 0;
42318
+ const raw = Math.min(avail, need);
42319
+ if (raw <= 0) return 0;
42320
+ if (minRoutable <= 0) return raw;
42321
+ return raw > minRoutable ? raw : 0;
42322
+ }
42323
+ function drawFunds(need, keys, pool, minRoutable) {
42192
42324
  const draws = {};
42193
42325
  let unmet = need;
42194
42326
  for (const k of keys) {
42195
42327
  if (unmet <= 0) break;
42196
42328
  const avail = pool[k];
42197
- if (avail <= 0) continue;
42198
- const take = Math.min(avail, unmet);
42329
+ const take = routableDrawAmount(avail, unmet, minRoutable);
42330
+ if (take <= 0) continue;
42199
42331
  draws[k] = take;
42200
42332
  pool[k] -= take;
42201
42333
  unmet -= take;
42202
42334
  }
42203
42335
  return { draws, filled: need - unmet, unmet };
42204
42336
  }
42337
+ function drawExtendedAggregated(need, pool, minRoutable) {
42338
+ const draws = {};
42339
+ if (need <= 0) return { draws, filled: 0, unmet: 0 };
42340
+ const totalCap = Math.max(0, pool.extAvlWithdraw) + Math.max(0, pool.extUpnl);
42341
+ const want = routableDrawAmount(totalCap, need, minRoutable);
42342
+ if (want <= 0) return { draws, filled: 0, unmet: need };
42343
+ const fromAvl = Math.min(Math.max(0, pool.extAvlWithdraw), want);
42344
+ pool.extAvlWithdraw -= fromAvl;
42345
+ const fromUpnl = Math.min(Math.max(0, pool.extUpnl), want - fromAvl);
42346
+ pool.extUpnl -= fromUpnl;
42347
+ if (fromAvl > 0) draws.extAvlWithdraw = fromAvl;
42348
+ if (fromUpnl > 0) draws.extUpnl = fromUpnl;
42349
+ const filled = fromAvl + fromUpnl;
42350
+ return { draws, filled, unmet: need - filled };
42351
+ }
42205
42352
  function sumKeys(draws, keys) {
42206
42353
  return keys.reduce((s, k) => s + (draws[k] ?? 0), 0);
42207
42354
  }
@@ -42212,33 +42359,39 @@ function applyDrawsToDeltas(d, draws, sign) {
42212
42359
  d.dExtAvlWithdraw += sign * (draws.extAvlWithdraw ?? 0);
42213
42360
  d.dExtUpnl += sign * (draws.extUpnl ?? 0);
42214
42361
  }
42215
- function fixExtMargin(ext, price, pool) {
42362
+ function fixExtMargin(ext, price, pool, config) {
42216
42363
  const d = emptyDeltas();
42217
42364
  const deficit = computeExtDeficit(ext, price);
42218
42365
  if (deficit <= 0) return { d, unmet: 0 };
42219
- const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
42366
+ const minR = config.minRoutableUsd ?? 0;
42367
+ const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool, minR);
42220
42368
  applyDrawsToDeltas(d, draws, -1);
42221
42369
  d.dExtAvlWithdraw += filled;
42222
42370
  const fromVesu = draws.vesuBorrowCapacity ?? 0;
42223
42371
  if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
42224
42372
  return { d, unmet };
42225
42373
  }
42226
- function fixVesuMargin(vesu, price, pool, hfBuffer) {
42374
+ function fixVesuMargin(vesu, price, pool, hfBuffer, config) {
42227
42375
  const d = emptyDeltas();
42228
42376
  const hf = computeVesuHF(vesu, price);
42229
42377
  if (hf >= vesu.targetHF - hfBuffer) return { d, unmet: 0 };
42230
42378
  const repayTokens = computeVesuDebtRepay(vesu, price);
42231
42379
  const repayUsd = repayTokens * vesu.debtPrice;
42232
- const { draws, filled, unmet } = drawFunds(repayUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
42233
- applyDrawsToDeltas(d, draws, -1);
42380
+ const minR = config.minRoutableUsd ?? 0;
42381
+ const rMain = drawFunds(repayUsd, ["vaUsd", "walletUsd"], pool, minR);
42382
+ applyDrawsToDeltas(d, rMain.draws, -1);
42383
+ const rExt = drawExtendedAggregated(rMain.unmet, pool, minR);
42384
+ applyDrawsToDeltas(d, rExt.draws, -1);
42385
+ const filled = rMain.filled + rExt.filled;
42386
+ const unmet = rExt.unmet;
42234
42387
  d.dVesuDebt -= filled / vesu.debtPrice;
42235
- const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
42388
+ const fromExt = sumKeys(rExt.draws, ["extAvlWithdraw", "extUpnl"]);
42236
42389
  if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
42237
42390
  return { d, unmet };
42238
42391
  }
42239
42392
  function phase1(ext, vesu, price, pool, config) {
42240
- const extResult = fixExtMargin(ext, price, pool);
42241
- const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer);
42393
+ const extResult = fixExtMargin(ext, price, pool, config);
42394
+ const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer, config);
42242
42395
  return {
42243
42396
  deltas: mergeDeltas(extResult.d, vesuResult.d),
42244
42397
  extDeficitRemaining: extResult.unmet,
@@ -42278,26 +42431,31 @@ function roundFinalPosition(extPos, vesuPos, rawF, precision) {
42278
42431
  }
42279
42432
  return Math.max(0, Math.min(fFromExt, fFromVesu));
42280
42433
  }
42281
- function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, precision) {
42434
+ function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, config) {
42282
42435
  const d = emptyDeltas();
42436
+ const precision = config.positionPrecision;
42437
+ const minR = config.minRoutableUsd ?? 0;
42283
42438
  const targetLTV = computeVesuTargetLTV(vesu);
42284
42439
  const imbalance = extPos - vesuPos;
42285
42440
  let fundedGrowthBtc = 0;
42286
42441
  if (!isNegligible(imbalance, precision)) {
42287
42442
  if (imbalance > 0) {
42288
42443
  const equityCostUsd = computeVesuGrowthCost(imbalance, vesu, price);
42289
- const { draws, filled } = drawFunds(equityCostUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
42290
- applyDrawsToDeltas(d, draws, -1);
42444
+ const rMain = drawFunds(equityCostUsd, ["vaUsd", "walletUsd"], pool, minR);
42445
+ applyDrawsToDeltas(d, rMain.draws, -1);
42446
+ const rExt = drawExtendedAggregated(rMain.unmet, pool, minR);
42447
+ applyDrawsToDeltas(d, rExt.draws, -1);
42448
+ const filled = rMain.filled + rExt.filled;
42291
42449
  const grownBtc = computeVesuGrowthFromEquity(filled, vesu, price);
42292
42450
  d.dVesuPosition += grownBtc;
42293
42451
  fundedGrowthBtc = grownBtc;
42294
42452
  d.dVesuDebt += computeVesuGrowthDebt(grownBtc, vesu, price);
42295
- const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
42453
+ const fromExt = sumKeys(rExt.draws, ["extAvlWithdraw", "extUpnl"]);
42296
42454
  if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
42297
42455
  } else {
42298
42456
  const absImbalance = -imbalance;
42299
42457
  const marginCostUsd = absImbalance * price / extLev;
42300
- const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
42458
+ const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool, minR);
42301
42459
  applyDrawsToDeltas(d, draws, -1);
42302
42460
  const grownBtc = filled * extLev / price;
42303
42461
  d.dExtPosition += grownBtc;
@@ -42338,6 +42496,7 @@ function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool,
42338
42496
  return d;
42339
42497
  }
42340
42498
  function rebalance(inputs) {
42499
+ logger.info(`ltv-imbalance-rebalance-math::rebalance inputs=${JSON.stringify(inputs)}`);
42341
42500
  const { ext, vesu, btcPrice, config } = inputs;
42342
42501
  const pool = { ...inputs.funding };
42343
42502
  const p1 = phase1(ext, vesu, btcPrice, pool, config);
@@ -42354,7 +42513,7 @@ function rebalance(inputs) {
42354
42513
  ext.leverage,
42355
42514
  btcPrice,
42356
42515
  pool,
42357
- config.positionPrecision
42516
+ config
42358
42517
  );
42359
42518
  return mergeDeltas(p1.deltas, p2);
42360
42519
  }
@@ -42935,15 +43094,15 @@ var SolveBudget = class {
42935
43094
  return this.vesuPoolStates[0];
42936
43095
  }
42937
43096
  // ── Derived getters (buffered where applicable) ─────────────────────
42938
- /** Buffered VA USD: strategy-asset slot + optional USDC slot. */
43097
+ /** Buffered VA USD: non-stable asset slot (if any) + USDC slot. */
42939
43098
  get vaUsd() {
42940
- return this.bufferedTokenUsd(this.vaultAssetBalance) + this.bufferedTokenUsd(this.vaultUsdcBalance);
43099
+ return this.bufferedTokenUsd(this.vaultUsdcBalance);
42941
43100
  }
42942
43101
  /** Buffered USD in VA strategy-asset bucket only. */
42943
43102
  get vaAssetUsd() {
42944
43103
  return this.bufferedTokenUsd(this.vaultAssetBalance);
42945
43104
  }
42946
- /** Buffered USD in VA USDC bucket (0 when asset === USDC). */
43105
+ /** Buffered USD in VA USDC bucket (includes full VA idle when asset === USDC). */
42947
43106
  get vaUsdcUsd() {
42948
43107
  return this.bufferedTokenUsd(this.vaultUsdcBalance);
42949
43108
  }
@@ -43025,9 +43184,13 @@ var SolveBudget = class {
43025
43184
  get vesuRebalanceFlags() {
43026
43185
  return this.shouldVesuRebalance;
43027
43186
  }
43028
- /** Raw USD in VA (USDC slot + asset slot); spend caps when executing transfers. */
43187
+ /** Raw USD in VA (USDC slot + non-stable asset slot when distinct); spend caps when executing transfers. */
43029
43188
  _vaRawUsd() {
43030
- return this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
43189
+ return this._rawTokenUsd(this.vaultUsdcBalance);
43190
+ }
43191
+ /** VA liquidity usable for repay / {@link spendVaRawUsd} (matches nominal balances after any {@link applyBuffer} scaling). */
43192
+ get vaRawUsd() {
43193
+ return this._vaRawUsd();
43031
43194
  }
43032
43195
  _walletRawUsd() {
43033
43196
  return this._rawTokenUsd(this.walletBalance);
@@ -43103,7 +43266,7 @@ var SolveBudget = class {
43103
43266
  rem -= fromUsdc;
43104
43267
  }
43105
43268
  if (rem > 0 && this.vaultAssetBalance) {
43106
- this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
43269
+ throw new Error(`Not implemented: spendVA with vaultAssetBalance`);
43107
43270
  }
43108
43271
  this._recomputeUnusedBalance();
43109
43272
  logger.debug(`SolveBudget::spendVA usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
@@ -43113,7 +43276,10 @@ var SolveBudget = class {
43113
43276
  * Spend nominal/raw USD from VA (e.g. Vesu repay, on-chain USDC). Does not apply the safety buffer to the cap.
43114
43277
  */
43115
43278
  spendVaRawUsd(rawUsdDesired) {
43116
- const capRaw = this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
43279
+ const capRaw = (
43280
+ // this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
43281
+ this._rawTokenUsd(this.vaultUsdcBalance)
43282
+ );
43117
43283
  const usedRaw = Math.min(capRaw, Math.max(0, rawUsdDesired));
43118
43284
  if (usedRaw <= CASE_THRESHOLD_USD) return 0;
43119
43285
  let rem = usedRaw;
@@ -43123,7 +43289,7 @@ var SolveBudget = class {
43123
43289
  rem -= fromUsdc;
43124
43290
  }
43125
43291
  if (rem > 0 && this.vaultAssetBalance) {
43126
- this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
43292
+ throw new Error(`Not implemented: spendVaRawUsd with vaultAssetBalance`);
43127
43293
  }
43128
43294
  this._recomputeUnusedBalance();
43129
43295
  logger.debug(`SolveBudget::spendVaRawUsd usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
@@ -43138,7 +43304,7 @@ var SolveBudget = class {
43138
43304
  if (this.vaultUsdcBalance) {
43139
43305
  this._addUsdToTokenBalance(this.vaultUsdcBalance, rawUsd);
43140
43306
  } else if (this.vaultAssetBalance) {
43141
- this._addUsdToTokenBalance(this.vaultAssetBalance, rawUsd);
43307
+ throw new Error(`Not implemented: addToVA with vaultAssetBalance`);
43142
43308
  }
43143
43309
  this._recomputeUnusedBalance();
43144
43310
  logger.debug(`SolveBudget::addToVA rawUsd=${rawUsd}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
@@ -43177,7 +43343,7 @@ var SolveBudget = class {
43177
43343
  if (isSpend) {
43178
43344
  const capRaw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
43179
43345
  const useRaw = Math.min(capRaw, desiredRaw);
43180
- if (useRaw <= CASE_THRESHOLD_USD) return 0;
43346
+ if (useRaw <= 0) return 0;
43181
43347
  rawDelta = -useRaw;
43182
43348
  } else {
43183
43349
  rawDelta = desiredRaw;
@@ -43197,7 +43363,7 @@ var SolveBudget = class {
43197
43363
  if (isSpend) {
43198
43364
  const capRaw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
43199
43365
  const useRaw = Math.min(capRaw, desiredRaw);
43200
- if (useRaw <= CASE_THRESHOLD_USD) return 0;
43366
+ if (useRaw <= 0) return 0;
43201
43367
  rawDelta = -useRaw;
43202
43368
  } else {
43203
43369
  rawDelta = desiredRaw;
@@ -43212,10 +43378,12 @@ var SolveBudget = class {
43212
43378
  return rawDelta;
43213
43379
  }
43214
43380
  spendExtAvailTrade(rawDesired) {
43215
- const used = this._updateExtAvailWithdraw(rawDesired, true);
43216
- const usedUpnl = this._updateExtAvailUpnl(rawDesired, true);
43217
- logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
43218
- return used + usedUpnl;
43381
+ const usedWd = this._updateExtAvailWithdraw(rawDesired, true);
43382
+ const tookWd = Math.abs(usedWd);
43383
+ const rem = rawDesired - tookWd;
43384
+ const usedUpnl = rem > 0 ? this._updateExtAvailUpnl(rem, true) : 0;
43385
+ logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${usedWd + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
43386
+ return usedWd + usedUpnl;
43219
43387
  }
43220
43388
  // simply reduces available amounts, but maintains equity and balance.
43221
43389
  spendExtAvailTradeToEquityOnly(rawDesired) {
@@ -43535,7 +43703,7 @@ var ExtendedSVKVesuStateManager = class {
43535
43703
  this._fetchExtendedPositions()
43536
43704
  ]);
43537
43705
  logger.verbose(
43538
- `${this._tag}::_refresh VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}${vaultUsdcBalance ? `, VA USDC=$${vaultUsdcBalance.usdValue.toFixed(2)}` : ""}, wallet=${walletBalance.usdValue}`
43706
+ `${this._tag}::_refresh ${vaultAssetBalance ? `VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}, ` : ""}VA USDC=${vaultUsdcBalance.usdValue.toFixed(2)}, wallet=${walletBalance.usdValue}`
43539
43707
  );
43540
43708
  const unusedBalance = this._computeUnusedBalances(
43541
43709
  vaultAssetBalance,
@@ -43560,23 +43728,28 @@ var ExtendedSVKVesuStateManager = class {
43560
43728
  },
43561
43729
  vesuPoolStates
43562
43730
  });
43731
+ this._budget.logStateSummary();
43563
43732
  const totalUnusedUsd = unusedBalance.reduce(
43564
43733
  (acc, b) => acc + b.usdValue,
43565
43734
  0
43566
43735
  );
43567
43736
  logger.info(
43568
- `${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()}`
43737
+ `${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()}`
43569
43738
  );
43570
43739
  }
43571
43740
  // todo add communication check with python server of extended. if not working, throw error in solve function.
43572
- /** True when strategy asset and USDC share one token — VA USDC slot is unused (all in asset balance). */
43741
+ /** True when strategy asset and USDC share one token — VA idle balance is tracked as USDC, not as asset. */
43573
43742
  _vaultAssetAndUsdcAreSameToken() {
43574
43743
  return this._config.assetToken.address.eq(this._config.usdcToken.address);
43575
43744
  }
43576
43745
  /**
43577
- * Reads the {@link StateManagerConfig.assetToken} balance idle in the vault allocator.
43746
+ * Reads idle {@link StateManagerConfig.assetToken} in the vault allocator when it differs from USDC.
43747
+ * When asset and USDC are the same token, returns null (that balance is reported via {@link _fetchVaultAllocatorUsdcBalanceIfDistinct} only).
43578
43748
  */
43579
43749
  async _fetchVaultAllocatorAssetBalance() {
43750
+ if (this._vaultAssetAndUsdcAreSameToken()) {
43751
+ return null;
43752
+ }
43580
43753
  const { assetToken, vaultAllocator, networkConfig, pricer } = this._config;
43581
43754
  const balance = await new ERC20(networkConfig).balanceOf(
43582
43755
  assetToken.address,
@@ -43588,11 +43761,9 @@ var ExtendedSVKVesuStateManager = class {
43588
43761
  return { token: assetToken, amount: balance, usdValue };
43589
43762
  }
43590
43763
  /**
43591
- * Reads {@link StateManagerConfig.usdcToken} in the vault allocator when it differs from
43592
- * {@link StateManagerConfig.assetToken}. Otherwise returns null (treat VA USDC as 0; stablecoin is only under asset).
43764
+ * Reads {@link StateManagerConfig.usdcToken} idle in the vault allocator (always distinct asset or USDC-as-asset).
43593
43765
  */
43594
43766
  async _fetchVaultAllocatorUsdcBalanceIfDistinct() {
43595
- if (this._vaultAssetAndUsdcAreSameToken()) return null;
43596
43767
  const { usdcToken, vaultAllocator, networkConfig, pricer } = this._config;
43597
43768
  const balance = await new ERC20(networkConfig).balanceOf(
43598
43769
  usdcToken.address,
@@ -43606,7 +43777,7 @@ var ExtendedSVKVesuStateManager = class {
43606
43777
  return { token: usdcToken, amount: balance, usdValue };
43607
43778
  }
43608
43779
  /**
43609
- * Merges vault-allocator asset, optional vault-allocator USDC, and operator wallet
43780
+ * Merges vault-allocator asset (if any), vault-allocator USDC, and operator wallet
43610
43781
  * balances into entries keyed by token address.
43611
43782
  */
43612
43783
  _computeUnusedBalances(vaultAssetBalance, vaultUsdcBalance, walletBalance) {
@@ -43618,8 +43789,8 @@ var ExtendedSVKVesuStateManager = class {
43618
43789
  usdValue: tb.usdValue
43619
43790
  });
43620
43791
  };
43621
- put(vaultAssetBalance);
43622
- if (vaultUsdcBalance) put(vaultUsdcBalance);
43792
+ if (vaultAssetBalance) put(vaultAssetBalance);
43793
+ put(vaultUsdcBalance);
43623
43794
  const key = walletBalance.token.address.toString();
43624
43795
  const existing = balanceMap.get(key);
43625
43796
  if (existing) {
@@ -44138,7 +44309,10 @@ var ExtendedSVKVesuStateManager = class {
44138
44309
  // ── ExecutionRoute-building helpers ─────────────────────────────────────────────
44139
44310
  // ── Atomic route builders ────────────────────────────────────────────
44140
44311
  _buildVesuRepayRoutes(totalUsd, routes) {
44141
- const { used, spendsByPool } = this._budget.repayVesuBorrowCapacity(totalUsd);
44312
+ const vaCap = this._budget.vaRawUsd;
44313
+ const repayUsd = Math.min(totalUsd, vaCap);
44314
+ if (repayUsd <= CASE_THRESHOLD_USD) return;
44315
+ const { used, spendsByPool } = this._budget.repayVesuBorrowCapacity(repayUsd);
44142
44316
  for (const route of spendsByPool) {
44143
44317
  routes.push({ type: "VESU_REPAY" /* VESU_REPAY */, ...route, priority: routes.length });
44144
44318
  }
@@ -44232,7 +44406,7 @@ var ExtendedSVKVesuStateManager = class {
44232
44406
  return { routes, remaining: tryAmount };
44233
44407
  }
44234
44408
  _getVAToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
44235
- const usable = Math.min(tryAmount, this._budget.vaUsd);
44409
+ const usable = Math.min(tryAmount, this._budget.vaUsdcUsd);
44236
44410
  if (usable > CASE_THRESHOLD_USD) {
44237
44411
  const vaUsed = this._budget.spendVA(usable);
44238
44412
  this._budget.addToExtAvailTrade(vaUsed);
@@ -44247,7 +44421,7 @@ var ExtendedSVKVesuStateManager = class {
44247
44421
  }
44248
44422
  _getExtendedToWalletRoute(tryAmount, routes, shouldAddWaitRoute = true) {
44249
44423
  if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
44250
- const rawCap = this._budget.extAvailWithdraw + this._budget.extAvailUpnl;
44424
+ const rawCap = this._budget.extAvailWithdraw + Math.max(0, this._budget.extAvailUpnl);
44251
44425
  const rawSpend = Math.min(tryAmount, rawCap);
44252
44426
  if (rawSpend <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
44253
44427
  const rawOut = this._budget.spendExtAvailTrade(rawSpend);
@@ -44437,7 +44611,9 @@ var ExtendedSVKVesuStateManager = class {
44437
44611
  * Design: accumulate all ext-to-wallet moves, add transfer routes at the end (principle #3).
44438
44612
  */
44439
44613
  /**
44440
- * Unified LTV classifier. Computes both Vesu repay and Extended margin needs,
44614
+ * Unified LTV / exposure classifier: `rebalance()` drives both LTV (debt, margin,
44615
+ * funding) and Vesu↔Extended position alignment. There is no separate imbalance pass.
44616
+ * Computes both Vesu repay and Extended margin needs,
44441
44617
  * then builds all routes in a single pass with no duplicate transfers.
44442
44618
  *
44443
44619
  * Vesu repay priority: VA > Wallet > ExtAvl > ExtUpnl
@@ -44493,7 +44669,8 @@ var ExtendedSVKVesuStateManager = class {
44493
44669
  },
44494
44670
  config: {
44495
44671
  positionPrecision: COLLATERAL_PRECISION,
44496
- hfBuffer: 0.05
44672
+ hfBuffer: 0.05,
44673
+ minRoutableUsd: CASE_THRESHOLD_USD
44497
44674
  }
44498
44675
  };
44499
44676
  }
@@ -44504,8 +44681,9 @@ var ExtendedSVKVesuStateManager = class {
44504
44681
  }
44505
44682
  /**
44506
44683
  * Turn pure rebalance() deltas into execution routes.
44507
- * Order: Vesu multiply (decrease/increase) → Extended lever → aggregated transfers
44508
- * (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED).
44684
+ * Order: Vesu multiply decrease → Extended decrease → aggregated transfers
44685
+ * (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED),
44686
+ * then Vesu multiply increase and Extended increase (need VA / Extended funded first).
44509
44687
  */
44510
44688
  _buildLtvRoutesFromRebalanceDeltas(d) {
44511
44689
  const routes = [];
@@ -44517,6 +44695,7 @@ var ExtendedSVKVesuStateManager = class {
44517
44695
  const targetLtv = VesuConfig.targetLtv;
44518
44696
  const btcEps = 10 ** -COLLATERAL_PRECISION;
44519
44697
  let multiplyDebtRepayUsd = 0;
44698
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas d=${JSON.stringify(d)}`);
44520
44699
  if (d.dVesuPosition < -btcEps) {
44521
44700
  const xBtc = -d.dVesuPosition;
44522
44701
  const transferUsdFromVesu = Math.max(0, d.dTransferVesuToExt);
@@ -44535,12 +44714,28 @@ var ExtendedSVKVesuStateManager = class {
44535
44714
  if (d.dVesuDebt < 0) {
44536
44715
  const needRepayUsd = -d.dVesuDebt * debtPrice;
44537
44716
  const multiplyRepayUsd = Math.min(needRepayUsd, swapLegMaxRepayUsd);
44717
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas ${JSON.stringify({
44718
+ needRepayUsd,
44719
+ multiplyRepayUsd
44720
+ })}`);
44538
44721
  debtTokenDelta = -(multiplyRepayUsd / debtPrice);
44539
44722
  } else {
44540
44723
  debtTokenDelta = -debtUsdFallback;
44541
44724
  }
44542
44725
  const debtAmtW3 = new Web3Number(debtTokenDelta.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
44543
44726
  multiplyDebtRepayUsd = Math.abs(debtTokenDelta) * debtPrice;
44727
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas ${JSON.stringify({
44728
+ debtTokenDelta,
44729
+ debtUsdFallback,
44730
+ swapLegMaxRepayUsd,
44731
+ xBtc,
44732
+ marginBtc,
44733
+ swappedBtc,
44734
+ transferUsdFromVesu,
44735
+ debtPrice,
44736
+ targetLtv,
44737
+ multiplyDebtRepayUsd
44738
+ })}`);
44544
44739
  routes.push({
44545
44740
  type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
44546
44741
  poolId: vesuAdapter.config.poolId,
@@ -44561,19 +44756,68 @@ var ExtendedSVKVesuStateManager = class {
44561
44756
  if (transferUsdFromVesu > CASE_THRESHOLD_USD) {
44562
44757
  this._budget.addToVA(transferUsdFromVesu);
44563
44758
  }
44564
- } else if (d.dVesuPosition > btcEps) {
44759
+ }
44760
+ if (d.dExtPosition < -btcEps) {
44761
+ const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
44762
+ routes.push({
44763
+ type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
44764
+ amount: amt,
44765
+ instrument,
44766
+ priority: routes.length
44767
+ });
44768
+ this._budget.applyExtendedExposureDelta(instrument, amt, price);
44769
+ }
44770
+ const negUpnl = Math.min(0, d.dExtUpnl);
44771
+ const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
44772
+ let hadExtendedOut = false;
44773
+ if (negUpnl < -CASE_THRESHOLD_USD) {
44774
+ this._getUpnlRoute(Math.abs(negUpnl), routes);
44775
+ hadExtendedOut = true;
44776
+ }
44777
+ const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
44778
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas extToWalletUsd=${extToWalletUsd}, negExtAvl=${negExtAvl}, negUpnl=${negUpnl}`);
44779
+ if (extToWalletUsd > CASE_THRESHOLD_USD) {
44780
+ this._getExtendedToWalletRoute(extToWalletUsd, routes);
44781
+ hadExtendedOut = true;
44782
+ } else {
44783
+ if (d.dVesuDebt < 0) {
44784
+ d.dVesuDebt += (negExtAvl < 0 && negExtAvl > -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < 0 && negUpnl > -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
44785
+ }
44786
+ }
44787
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas d=${JSON.stringify(d)}`);
44788
+ const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
44789
+ const walletToVaUsd = walletPull + extToWalletUsd;
44790
+ if (walletToVaUsd > CASE_THRESHOLD_USD) {
44791
+ this._getWALLETToVARoute(walletToVaUsd, routes);
44792
+ }
44793
+ if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
44794
+ this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
44795
+ }
44796
+ const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
44797
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas totalDebtRepayUsd=${totalDebtRepayUsd}`);
44798
+ let standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
44799
+ logger.info(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas standaloneRepayUsd=${standaloneRepayUsd}`);
44800
+ if (standaloneRepayUsd > this._budget.vaRawUsd) {
44801
+ if (Math.abs(standaloneRepayUsd - this._budget.vaRawUsd) < CASE_THRESHOLD_USD) {
44802
+ standaloneRepayUsd = this._budget.vaRawUsd;
44803
+ } else {
44804
+ throw new Error(`${this._tag}::_buildLtvRoutesFromRebalanceDeltas standaloneRepayUsd=${standaloneRepayUsd} > vaRawUsd=${this._budget.vaRawUsd}`);
44805
+ }
44806
+ }
44807
+ if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
44808
+ this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
44809
+ }
44810
+ const posExtEq = Math.max(0, d.dExtAvlWithdraw);
44811
+ const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
44812
+ if (vaToExtUsd > CASE_THRESHOLD_USD) {
44813
+ this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
44814
+ }
44815
+ if (d.dVesuPosition > btcEps) {
44565
44816
  const vesuDepositAmount = new Web3Number(
44566
44817
  (d.dVesuPosition * price * (1 - targetLtv)).toFixed(USDC_TOKEN_DECIMALS),
44567
44818
  USDC_TOKEN_DECIMALS
44568
44819
  );
44569
44820
  if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
44570
- routes.push({
44571
- type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
44572
- priority: routes.length,
44573
- fromToken: vesuAdapter.config.collateral.symbol,
44574
- fromAmount: vesuDepositAmount,
44575
- toToken: vesuAdapter.config.debt.symbol
44576
- });
44577
44821
  }
44578
44822
  const collateralDelta = new Web3Number(
44579
44823
  d.dVesuPosition.toFixed(COLLATERAL_PRECISION),
@@ -44584,8 +44828,9 @@ var ExtendedSVKVesuStateManager = class {
44584
44828
  new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
44585
44829
  );
44586
44830
  const collPx = pool.collateralPrice || 1;
44831
+ const marginUsdAmount = externalDepositAmount.toNumber() * (pool.debtPrice ?? 1);
44587
44832
  const swappedAmount = new Web3Number(
44588
- (externalDepositAmount.toNumber() * (pool.debtPrice ?? 1) / collPx).toFixed(6),
44833
+ (marginUsdAmount / collPx).toFixed(6),
44589
44834
  vesuAdapter.config.collateral.decimals
44590
44835
  );
44591
44836
  const debtDeltaTokens = new Web3Number(
@@ -44609,17 +44854,9 @@ var ExtendedSVKVesuStateManager = class {
44609
44854
  collateralDelta,
44610
44855
  debtDeltaTokens
44611
44856
  );
44857
+ this._budget.spendVA(marginUsdAmount);
44612
44858
  }
44613
- if (d.dExtPosition < -btcEps) {
44614
- const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
44615
- routes.push({
44616
- type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
44617
- amount: amt,
44618
- instrument,
44619
- priority: routes.length
44620
- });
44621
- this._budget.applyExtendedExposureDelta(instrument, amt, price);
44622
- } else if (d.dExtPosition > btcEps) {
44859
+ if (d.dExtPosition > btcEps) {
44623
44860
  const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
44624
44861
  routes.push({
44625
44862
  type: "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
@@ -44629,36 +44866,6 @@ var ExtendedSVKVesuStateManager = class {
44629
44866
  });
44630
44867
  this._budget.applyExtendedExposureDelta(instrument, amt, price);
44631
44868
  }
44632
- const negUpnl = Math.min(0, d.dExtUpnl);
44633
- const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
44634
- let hadExtendedOut = false;
44635
- if (negUpnl < -CASE_THRESHOLD_USD) {
44636
- this._getUpnlRoute(Math.abs(negUpnl), routes);
44637
- hadExtendedOut = true;
44638
- }
44639
- const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
44640
- if (extToWalletUsd > CASE_THRESHOLD_USD) {
44641
- this._getExtendedToWalletRoute(extToWalletUsd, routes);
44642
- hadExtendedOut = true;
44643
- }
44644
- const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
44645
- const walletToVaUsd = walletPull + extToWalletUsd;
44646
- if (walletToVaUsd > CASE_THRESHOLD_USD) {
44647
- this._getWALLETToVARoute(walletToVaUsd, routes);
44648
- }
44649
- if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
44650
- this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
44651
- }
44652
- const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
44653
- const standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
44654
- if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
44655
- this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
44656
- }
44657
- const posExtEq = Math.max(0, d.dExtAvlWithdraw);
44658
- const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
44659
- if (vaToExtUsd > CASE_THRESHOLD_USD) {
44660
- this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
44661
- }
44662
44869
  return routes;
44663
44870
  }
44664
44871
  // ── LTV Vesu route builders ───────────────────────────────────────────
@@ -44817,48 +45024,76 @@ var ExtendedSVKVesuStateManager = class {
44817
45024
  const extendedTarget = total / (1 + extendedLeverage / vesuLeverage);
44818
45025
  const extendedInitial = extAvlWithdraw + extUpnl;
44819
45026
  let delta = extendedTarget - extendedInitial;
44820
- let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0;
45027
+ let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0, finalVaUsd = vaUsd, finalExtended = extAvlWithdraw + Math.max(extUpnl, 0);
44821
45028
  if (delta > 0) {
44822
45029
  let need = delta;
44823
- const takeWalletUsd = Math.min(walletUsd, need);
45030
+ const eps = CASE_THRESHOLD_USD;
45031
+ const takeWalletUsd = routableDrawAmount(walletUsd, need, eps);
44824
45032
  dWalletUsd -= takeWalletUsd;
44825
45033
  need -= takeWalletUsd;
44826
- const takeVaUsd = Math.min(vaUsd, need);
45034
+ const takeVaUsd = routableDrawAmount(vaUsd, need, eps);
44827
45035
  dVaUsd -= takeVaUsd;
44828
45036
  need -= takeVaUsd;
44829
- const takeVesuBorrowCapacity = Math.min(vesuBorrowCapacity, need);
45037
+ finalVaUsd -= takeVaUsd;
45038
+ finalVaUsd += walletUsd - takeWalletUsd;
45039
+ const takeVesuBorrowCapacity = routableDrawAmount(vesuBorrowCapacity, need, eps);
44830
45040
  dVesuBorrowCapacity -= takeVesuBorrowCapacity;
44831
45041
  need -= takeVesuBorrowCapacity;
45042
+ finalVaUsd += vesuBorrowCapacity - takeVesuBorrowCapacity;
44832
45043
  const received = delta - need;
44833
45044
  const eco1Sum = extAvlWithdraw + extUpnl;
45045
+ finalExtended += received;
44834
45046
  if (eco1Sum >= 0) {
44835
45047
  dExtAvlWithdraw += received;
44836
45048
  } else {
44837
- throw new Error(`${this._tag}: Unexpected case`);
45049
+ const hole = -eco1Sum;
45050
+ const fillUpnl = Math.min(received, hole);
45051
+ dExtUpnl += fillUpnl;
45052
+ dExtAvlWithdraw += received - fillUpnl;
45053
+ finalExtended -= fillUpnl;
44838
45054
  }
44839
- if (need > 0) {
45055
+ if (need > CASE_THRESHOLD_USD) {
44840
45056
  throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
44841
45057
  }
44842
45058
  } else if (delta < 0) {
44843
45059
  let need = -delta;
44844
- const takeExtAvlWithdraw = Math.min(extAvlWithdraw, need);
45060
+ const takeExtAvlWithdraw = Math.min(Math.max(extAvlWithdraw, 0), need);
44845
45061
  dExtAvlWithdraw -= takeExtAvlWithdraw;
44846
- need -= takeExtAvlWithdraw;
44847
- const takeExtUpnl = Math.min(extUpnl, need);
45062
+ const takeExtUpnl = Math.min(Math.max(extUpnl, 0), need);
44848
45063
  dExtUpnl -= takeExtUpnl;
44849
- need -= takeExtUpnl;
45064
+ const netDrawableAmount = takeExtAvlWithdraw + takeExtUpnl;
45065
+ if (netDrawableAmount > CASE_THRESHOLD_USD) {
45066
+ need -= netDrawableAmount;
45067
+ finalExtended -= netDrawableAmount;
45068
+ }
44850
45069
  const sent = -delta - need;
44851
45070
  const eco2Sum = vaUsd + walletUsd + vesuBorrowCapacity;
45071
+ const netWalletUsd = walletUsd < CASE_THRESHOLD_USD ? 0 : walletUsd;
45072
+ finalVaUsd += sent + netWalletUsd;
44852
45073
  if (eco2Sum >= 0) {
44853
45074
  dWalletUsd += sent;
44854
45075
  } else {
44855
45076
  throw new Error(`${this._tag}: Unexpected case`);
44856
45077
  }
44857
- if (need > 0) {
45078
+ if (need > CASE_THRESHOLD_USD) {
44858
45079
  throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
44859
45080
  }
44860
45081
  }
44861
- return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu: delta < 0 };
45082
+ return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, finalVaUsd, finalExtended, isExtendedToVesu: delta < 0 };
45083
+ }
45084
+ _scaleVesuPoolDeltasByFactor(deltas, scale) {
45085
+ if (scale >= 1 - 1e-15) return deltas;
45086
+ return deltas.map((d) => ({
45087
+ ...d,
45088
+ collateralDelta: new Web3Number(
45089
+ (d.collateralDelta.toNumber() * scale).toFixed(COLLATERAL_PRECISION),
45090
+ d.collateralToken.decimals
45091
+ ),
45092
+ debtDelta: new Web3Number(
45093
+ (d.debtDelta.toNumber() * scale).toFixed(USDC_TOKEN_DECIMALS),
45094
+ USDC_TOKEN_DECIMALS
45095
+ )
45096
+ }));
44862
45097
  }
44863
45098
  /**
44864
45099
  * 3. New Deposits / Excess Funds
@@ -44874,6 +45109,11 @@ var ExtendedSVKVesuStateManager = class {
44874
45109
  * Computes allocation split between Vesu and Extended, then sources
44875
45110
  * funds and creates lever-increase routes.
44876
45111
  *
45112
+ * Order: {@link _rebalanceFunds} first → project VA / Extended liquid after the same funding
45113
+ * routes (wallet→VA, borrow→VA, VA→Extended, Extended→wallet→VA) → ideal Vesu/Extended deltas
45114
+ * from distributable split → cap common BTC by min(Vesu fundable, Extended fundable) → scale
45115
+ * Vesu deltas and recompute Extended deltas so both sides stay matched.
45116
+ *
44877
45117
  * Fund flow (single pass — avoid VA→Extended then Extended→wallet round-trips):
44878
45118
  * 1) Treat Vesu borrow headroom that the multiply route will consume as covering
44879
45119
  * part of the Vesu USDC need (no standalone VESU_BORROW for that slice). Cap
@@ -44896,15 +45136,9 @@ var ExtendedSVKVesuStateManager = class {
44896
45136
  withdrawAmount
44897
45137
  );
44898
45138
  if (distributableAmount.toNumber() <= CASE_THRESHOLD_USD) return [];
44899
- const { vesuAllocationUsd, extendedAllocationUsd } = this._computeAllocationSplit(distributableAmount);
44900
- const vesuDeltas = this._computePerPoolCollateralDeltas(
44901
- vesuAllocationUsd
44902
- );
44903
- const extendedPositionDeltas = this._computeExtendedPositionDeltas(vesuDeltas);
44904
- const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
44905
45139
  const vesuLeverage = calculateVesuLeverage();
44906
45140
  const extendedLeverage = calculateExtendedLevergae();
44907
- const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu } = this._rebalanceFunds({
45141
+ const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu, finalVaUsd, finalExtended } = this._rebalanceFunds({
44908
45142
  extAvlWithdraw: this._budget.extAvailWithdraw,
44909
45143
  extUpnl: this._budget.extAvailUpnl,
44910
45144
  vaUsd: this._budget.vaUsd,
@@ -44913,6 +45147,23 @@ var ExtendedSVKVesuStateManager = class {
44913
45147
  vesuLeverage,
44914
45148
  extendedLeverage
44915
45149
  });
45150
+ logger.info(`${this._tag}::_classifyDeposits dExtAvlWithdraw=${dExtAvlWithdraw}, dExtUpnl=${dExtUpnl}, dVaUsd=${dVaUsd}, dWalletUsd=${dWalletUsd}, dVesuBorrowCapacity=${dVesuBorrowCapacity}, isExtendedToVesu=${isExtendedToVesu}, finalVaUsd=${finalVaUsd}`);
45151
+ let vesuDeltas = this._computePerPoolCollateralDeltas(new Web3Number(finalVaUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS));
45152
+ const collateralPrice = this._budget.vesuPools[0]?.collateralPrice ?? 0;
45153
+ const collateralDecimals = this._budget.vesuPools[0]?.collateralToken.decimals ?? 0;
45154
+ let _extendedPositionDelta = new Web3Number((finalExtended * extendedLeverage / collateralPrice).toFixed(USDC_TOKEN_DECIMALS), collateralDecimals).toFixedRoundDown(COLLATERAL_PRECISION);
45155
+ logger.info(`${this._tag}::_classifyDeposits extendedPositionDelta=${_extendedPositionDelta}`);
45156
+ logger.info(`${this._tag}::_classifyDeposits vesuDeltas=${JSON.stringify(vesuDeltas)}`);
45157
+ assert(vesuDeltas.length == 1, "vesuDeltas should have only one delta");
45158
+ const minPositionDelta = Math.min(vesuDeltas[0].collateralDelta.toNumber(), Number(_extendedPositionDelta));
45159
+ logger.info(`${this._tag}::_classifyDeposits minPositionDelta=${minPositionDelta}`);
45160
+ vesuDeltas[0].collateralDelta = new Web3Number(minPositionDelta.toFixed(COLLATERAL_PRECISION), vesuDeltas[0].collateralDelta.decimals);
45161
+ const extendedPositionDeltas = [{
45162
+ instrument: this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD",
45163
+ delta: new Web3Number(minPositionDelta.toFixed(COLLATERAL_PRECISION), collateralDecimals)
45164
+ }];
45165
+ const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
45166
+ logger.info(`${this._tag}::_classifyDeposits vesuDepositAmount=${vesuDepositAmount}`);
44916
45167
  const routes = [];
44917
45168
  if (isExtendedToVesu) {
44918
45169
  if (dExtUpnl < 0) {
@@ -44940,13 +45191,6 @@ var ExtendedSVKVesuStateManager = class {
44940
45191
  }
44941
45192
  for (const vesuDelta of vesuDeltas) {
44942
45193
  if (!skipAvnuDepositSwap && vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
44943
- routes.push({
44944
- type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
44945
- priority: routes.length,
44946
- fromToken: vesuDelta.collateralToken.symbol,
44947
- fromAmount: vesuDepositAmount,
44948
- toToken: vesuDelta.debtToken.symbol
44949
- });
44950
45194
  }
44951
45195
  if (vesuDelta.collateralDelta.toNumber() > 0) {
44952
45196
  const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
@@ -45926,14 +46170,6 @@ var _ExecutionService = class _ExecutionService {
45926
46170
  );
45927
46171
  return this._executeStandardCase(caseEntry, activeRoutes);
45928
46172
  }
45929
- const setLevResult = await this._config.extendedAdapter.setLeverage(calculateExtendedLevergae().toString(), this._config.extendedAdapter.config.extendedMarketName);
45930
- if (!setLevResult) {
45931
- logger.error(
45932
- `${this._tag}::_executeCoordinatedCase failed to set leverage`
45933
- );
45934
- results.push(this._failureResult(extendedRoute));
45935
- return results;
45936
- }
45937
46173
  const isIncrease = _ExecutionService.INCREASE_EXPOSURE_ROUTES.has(
45938
46174
  extendedRoute.type
45939
46175
  );
@@ -45954,8 +46190,9 @@ var _ExecutionService = class _ExecutionService {
45954
46190
  onChainCalls = callArrays.flat();
45955
46191
  } catch (err) {
45956
46192
  logger.error(
45957
- `${this._tag}::_executeCoordinatedCase on-chain call construction failed: ${err}`
46193
+ `${this._tag}::_executeCoordinatedCase on-chain call construction failed:`
45958
46194
  );
46195
+ console.error(err);
45959
46196
  await this._emitEvent("FAILURE" /* FAILURE */, {
45960
46197
  routeSummary: `coordinated on-chain build for case "${caseEntry.case.id}"`,
45961
46198
  error: `${err}`
@@ -46027,7 +46264,7 @@ var _ExecutionService = class _ExecutionService {
46027
46264
  }
46028
46265
  const timeoutMs = this._config.extendedFillTimeoutMs ?? DEFAULT_EXTENDED_FILL_TIMEOUT_MS;
46029
46266
  const extResult = await this._executeExtendedLimitOrderWithRecovery(
46030
- btcAmount,
46267
+ Math.abs(btcAmount),
46031
46268
  executionPrice,
46032
46269
  side,
46033
46270
  {
@@ -46555,7 +46792,7 @@ var _ExecutionService = class _ExecutionService {
46555
46792
  return this._failureResult(route);
46556
46793
  }
46557
46794
  const closeResult = await this._executeExtendedLimitOrderWithRecovery(
46558
- positionToClose.toNumber(),
46795
+ Math.abs(positionToClose.toNumber()),
46559
46796
  midPrice,
46560
46797
  "BUY" /* BUY */
46561
46798
  );
@@ -46573,7 +46810,7 @@ var _ExecutionService = class _ExecutionService {
46573
46810
  `${this._tag}::_executeRealisePnl reopening ${positionToClose.toNumber()} on ${route.instrument}`
46574
46811
  );
46575
46812
  const reopenResult = await this._executeExtendedLimitOrderWithRecovery(
46576
- positionToClose.toNumber(),
46813
+ Math.abs(positionToClose.toNumber()),
46577
46814
  midPrice,
46578
46815
  "SELL" /* SELL */
46579
46816
  );
@@ -46627,7 +46864,7 @@ var _ExecutionService = class _ExecutionService {
46627
46864
  return this._failureResult(route);
46628
46865
  }
46629
46866
  const result = await this._executeExtendedLimitOrderWithRecovery(
46630
- route.amount.toNumber(),
46867
+ Math.abs(route.amount.toNumber()),
46631
46868
  midPrice,
46632
46869
  "SELL" /* SELL */
46633
46870
  );
@@ -46675,7 +46912,7 @@ var _ExecutionService = class _ExecutionService {
46675
46912
  return this._failureResult(route);
46676
46913
  }
46677
46914
  const result = await this._executeExtendedLimitOrderWithRecovery(
46678
- route.amount.toNumber(),
46915
+ Math.abs(route.amount.toNumber()),
46679
46916
  midPrice,
46680
46917
  "BUY" /* BUY */
46681
46918
  );
@@ -47298,16 +47535,16 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
47298
47535
  ];
47299
47536
  }
47300
47537
  };
47301
- function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47538
+ function getLooperSettings3(collateralSymbol, underlyingSymbol, vaultSettings, pool1, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47302
47539
  vaultSettings.leafAdapters = [];
47303
47540
  const wbtcToken = Global.getDefaultTokens().find(
47304
- (token) => token.symbol === lstSymbol
47541
+ (token) => token.symbol === collateralSymbol
47305
47542
  );
47306
47543
  const usdcToken = Global.getDefaultTokens().find(
47307
47544
  (token) => token.symbol === underlyingSymbol
47308
47545
  );
47309
47546
  const baseAdapterConfig = {
47310
- baseToken: wbtcToken,
47547
+ baseToken: usdcToken,
47311
47548
  supportedPositions: [
47312
47549
  { asset: usdcToken, isDebt: true },
47313
47550
  { asset: wbtcToken, isDebt: false }
@@ -47407,7 +47644,7 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
47407
47644
  vaultAddress: vaultSettings.vaultAddress,
47408
47645
  vaultAllocator: vaultSettings.vaultAllocator,
47409
47646
  manager: vaultSettings.manager,
47410
- asset: wbtcToken.address
47647
+ asset: usdcToken.address
47411
47648
  });
47412
47649
  vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getDepositLeaf());
47413
47650
  vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getWithdrawLeaf());
@@ -47541,6 +47778,39 @@ var re7UsdcPrimeDevansh = {
47541
47778
  minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
47542
47779
  walletAddress: "0x024b563C1C7d41B32BF4EFB9F38828508a65Be2d6e25268E9f63F22C5e9E51c5"
47543
47780
  };
47781
+ var pureUsdc = {
47782
+ vaultAddress: ContractAddr.from(
47783
+ "0x745c972db65bdee10022fd875dd328c7f40a90849135b6a0f875a40f3c632ae"
47784
+ ),
47785
+ manager: ContractAddr.from(
47786
+ "0x364e0894edefb616ec090f57f5c0274517fcd98ab276ae1f021c5e962fa1deb"
47787
+ ),
47788
+ vaultAllocator: ContractAddr.from(
47789
+ "0x6fceed28e03a96091877568893df0dd89b9bb80fec30da2b742dacbd5526179"
47790
+ ),
47791
+ redeemRequestNFT: ContractAddr.from(
47792
+ "0x501c2b87728e22c6dfcebe4c0b2b3a9fba5845606e4d59fa7bf591badcbb42"
47793
+ ),
47794
+ aumOracle: ContractAddr.from(
47795
+ "0x6ccd95f5765242695d3c75e1440b1d0b30efac8babb864ce15729977b97cb82"
47796
+ ),
47797
+ leafAdapters: [],
47798
+ adapters: [],
47799
+ targetHealthFactor: 1.4,
47800
+ minHealthFactor: 1.35,
47801
+ underlyingToken: Global.getDefaultTokens().find(
47802
+ (token) => token.symbol === "USDC"
47803
+ ),
47804
+ quoteAmountToFetchPrice: new Web3Number(
47805
+ "0.001",
47806
+ Global.getDefaultTokens().find((token) => token.symbol === "USDC").decimals
47807
+ ),
47808
+ borrowable_assets: [
47809
+ Global.getDefaultTokens().find((token) => token.symbol === "USDC")
47810
+ ],
47811
+ minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
47812
+ walletAddress: "0x058571C23da5FEdd4e36003FAE3fE2fA9782f2692E552f081839142B10770D0B"
47813
+ };
47544
47814
  var VesuExtendedTestStrategies = (extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) => {
47545
47815
  return [
47546
47816
  getStrategySettingsVesuExtended(
@@ -47557,14 +47827,29 @@ var VesuExtendedTestStrategies = (extendedBackendReadUrl, extendedBackendWriteUr
47557
47827
  minimumExtendedRetriesDelayForOrderStatus,
47558
47828
  minimumExtendedPriceDifferenceForSwapOpen,
47559
47829
  maximumExtendedPriceDifferenceForSwapClosing
47830
+ ),
47831
+ getStrategySettingsVesuExtended(
47832
+ "WBTC",
47833
+ "USDC",
47834
+ pureUsdc,
47835
+ false,
47836
+ false,
47837
+ extendedBackendReadUrl,
47838
+ extendedBackendWriteUrl,
47839
+ vaultIdExtended,
47840
+ minimumExtendedMovementAmount,
47841
+ minimumVesuMovementAmount,
47842
+ minimumExtendedRetriesDelayForOrderStatus,
47843
+ minimumExtendedPriceDifferenceForSwapOpen,
47844
+ maximumExtendedPriceDifferenceForSwapClosing
47560
47845
  )
47561
47846
  ];
47562
47847
  };
47563
- function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses, isPreview = false, isLST, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47848
+ function getStrategySettingsVesuExtended(collateralSymbol, underlyingSymbol, addresses, isPreview = false, isLST, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
47564
47849
  return {
47565
47850
  id: `extended_${underlyingSymbol.toLowerCase()}_test`,
47566
47851
  name: `Extended Test ${underlyingSymbol}`,
47567
- description: getDescription3(lstSymbol, underlyingSymbol),
47852
+ description: getDescription3(collateralSymbol, underlyingSymbol),
47568
47853
  address: addresses.vaultAddress,
47569
47854
  launchBlock: 0,
47570
47855
  type: "Other",
@@ -47578,7 +47863,7 @@ function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses,
47578
47863
  )
47579
47864
  ],
47580
47865
  additionalInfo: getLooperSettings3(
47581
- lstSymbol,
47866
+ collateralSymbol,
47582
47867
  underlyingSymbol,
47583
47868
  addresses,
47584
47869
  VesuPools.Re7USDCPrime,
@@ -47599,8 +47884,8 @@ function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses,
47599
47884
  auditUrl: AUDIT_URL4,
47600
47885
  protocols: [Protocols.ENDUR, Protocols.VESU],
47601
47886
  contractDetails: getContractDetails(addresses),
47602
- faqs: getFAQs2(lstSymbol, underlyingSymbol, isLST),
47603
- investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
47887
+ faqs: getFAQs2(collateralSymbol, underlyingSymbol, isLST),
47888
+ investmentSteps: getInvestmentSteps(collateralSymbol, underlyingSymbol),
47604
47889
  isPreview,
47605
47890
  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.",
47606
47891
  security: {