@strkfarm/sdk 2.0.0-dev.33 → 2.0.0-dev.35

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
@@ -21734,6 +21734,7 @@ import { CairoCustomEnum as CairoCustomEnum2, Contract as Contract10, hash as ha
21734
21734
 
21735
21735
  // src/strategies/universal-adapters/adapter-utils.ts
21736
21736
  var SIMPLE_SANITIZER = ContractAddr.from("0x5a2e3ceb3da368b983a8717898427ab7b6daf04014b70f321e777f9aad940b4");
21737
+ var SVK_SIMPLE_SANITIZER = ContractAddr.from("0x03dcde04343257c3ce14574676cb9c5b2eda16e332c1b8caf5dc4c95ac568d2f");
21737
21738
  var EXTENDED_SANITIZER = ContractAddr.from("0x65891708362b24dcf4c40c8e218cce6e82d1d6b3a3404c9ab00a48f08e2c110");
21738
21739
  var AVNU_LEGACY_SANITIZER = ContractAddr.from("0x0656fBE853f116DD53956176a553eDe8fE65632252f8aceB50C1B9B6c8237309");
21739
21740
  var SIMPLE_SANITIZER_V2 = ContractAddr.from("0x7b6f98311af8aa425278570e62abf523e6462eaa01a38c1feab9b2f416492e2");
@@ -35597,7 +35598,14 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
35597
35598
  }
35598
35599
  const normalizedDebtAmount = this._normalizeDebtAmountFromHelper(
35599
35600
  helperOutput
35600
- );
35601
+ ).minus(state.currentDebt);
35602
+ if (normalizedDebtAmount.lessThan(0)) {
35603
+ logger.warn(`VesuModifyPositionAdapter: deposit debt delta is negative (${normalizedDebtAmount.toNumber()}), clamping to zero`);
35604
+ return {
35605
+ collateral: this._toSigned(collateralToAdd, false),
35606
+ debt: this._toSigned(Web3Number.fromWei(0, this.config.debt.decimals), false)
35607
+ };
35608
+ }
35601
35609
  return {
35602
35610
  collateral: this._toSigned(collateralToAdd, false),
35603
35611
  debt: this._toSigned(normalizedDebtAmount, false)
@@ -35615,8 +35623,8 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
35615
35623
  state.debtPrice,
35616
35624
  this.config.debt
35617
35625
  );
35618
- if (!helperOutput || helperOutput.greaterThan(0)) {
35619
- throw new Error(`Failed to calculate default withdraw debt delta: ${helperOutput?.toNumber()}`);
35626
+ if (!helperOutput || helperOutput.lessThan(0)) {
35627
+ throw new Error(`Failed to calculate max debt amount for withdraw: ${helperOutput?.toNumber()}`);
35620
35628
  }
35621
35629
  const normalizedDebtAmount = this._normalizeDebtAmountFromHelper(
35622
35630
  helperOutput
@@ -35813,6 +35821,24 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
35813
35821
  this._prepareVesuAdapter();
35814
35822
  return this._vesuAdapter.getHealthFactor();
35815
35823
  }
35824
+ /**
35825
+ * Simulates a deposit of `depositAmount` collateral and returns how much
35826
+ * debt (STRK) would be incrementally borrowed to reach the target LTV.
35827
+ * Used upstream to size the AVNU swap call in the same transaction batch.
35828
+ */
35829
+ async getExpectedDepositDebtDelta(depositAmount) {
35830
+ const defaults = await this._buildDefaultDepositDeltas({ amount: depositAmount });
35831
+ return defaults.debt.amount;
35832
+ }
35833
+ /**
35834
+ * Simulates a withdrawal of `withdrawAmount` collateral and returns the
35835
+ * incremental debt delta needed to keep the target health factor.
35836
+ * Positive means borrow, negative means repay.
35837
+ */
35838
+ async getExpectedWithdrawDebtDelta(withdrawAmount) {
35839
+ const defaults = await this._buildDefaultWithdrawDeltas({ amount: withdrawAmount });
35840
+ return defaults.debt.amount;
35841
+ }
35816
35842
  };
35817
35843
 
35818
35844
  // src/strategies/universal-adapters/extended-adapter.ts
@@ -36370,6 +36396,25 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
36370
36396
  return { success: false, data: [] };
36371
36397
  }
36372
36398
  }
36399
+ /** Account funding payment history via `GET /api/v1/account/funding-payments` (USDC amounts). */
36400
+ async getFundingPayments(side, startTime, limit) {
36401
+ try {
36402
+ const response = await this.client.getUserFundingPayments(
36403
+ this.config.extendedMarketName,
36404
+ side,
36405
+ startTime ?? Date.now() - 30 * 24 * 60 * 60 * 1e3,
36406
+ limit ?? 200
36407
+ );
36408
+ if (response.status !== "OK") {
36409
+ logger.error("error getting funding payments", response.data);
36410
+ return { success: false, data: [] };
36411
+ }
36412
+ return { success: true, data: response.data ?? [] };
36413
+ } catch (err) {
36414
+ logger.error("error getting funding payments", err);
36415
+ return { success: false, data: [] };
36416
+ }
36417
+ }
36373
36418
  async getPosition(supportedPosition) {
36374
36419
  const holdings = await this.getExtendedDepositAmount();
36375
36420
  if (!holdings) {
@@ -39009,228 +39054,1076 @@ var universal_vault_abi_default = [
39009
39054
  }
39010
39055
  ];
39011
39056
 
39012
- // src/strategies/universal-adapters/svk-troves-adapter.ts
39013
- var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
39014
- function parseTrovesApyField(raw) {
39015
- if (typeof raw === "number" && Number.isFinite(raw)) {
39016
- return raw;
39017
- }
39018
- if (typeof raw === "string") {
39019
- const n = Number.parseFloat(raw);
39020
- if (Number.isFinite(n)) {
39021
- return n;
39022
- }
39023
- }
39024
- return 0;
39025
- }
39026
- var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
39027
- constructor(config) {
39028
- super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
39029
- this.config = config;
39030
- }
39031
- /** Owner used for share balance + `due_assets_from_owner`. */
39032
- _positionOwner() {
39033
- return this.config.positionOwner ?? this.config.vaultAllocator;
39034
- }
39035
- /**
39036
- * Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
39037
- * `strategyVault` address so multiple SVK adapters in one tree stay distinct.
39038
- */
39039
- _proofSuffix() {
39040
- return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
39041
- }
39042
- _depositApproveProofReadableId() {
39043
- return `appr_dep_svk_${this._proofSuffix()}`;
39044
- }
39045
- _depositCallProofReadableId() {
39046
- return `dep_svk_${this._proofSuffix()}`;
39047
- }
39048
- _withdrawCallProofReadableId() {
39049
- return `wtdrw_svk_${this._proofSuffix()}`;
39050
- }
39051
- async getAPY(supportedPosition) {
39052
- const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
39053
- const cached = this.getCache(CACHE_KEY);
39054
- if (cached) {
39055
- return cached;
39056
- }
39057
- const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
39058
- try {
39059
- const res = await fetch(url);
39060
- if (!res.ok) {
39061
- logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
39062
- const fallback = { apy: 0, type: "base" /* BASE */ };
39063
- this.setCache(CACHE_KEY, fallback, 3e5);
39064
- return fallback;
39065
- }
39066
- const body = await res.json();
39067
- const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
39068
- if (!row) {
39069
- logger.warn(
39070
- `${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
39071
- );
39072
- const fallback = { apy: 0, type: "base" /* BASE */ };
39073
- this.setCache(CACHE_KEY, fallback, 3e5);
39074
- return fallback;
39075
- }
39076
- const apy = parseTrovesApyField(row.apy);
39077
- const result = { apy, type: "base" /* BASE */ };
39078
- this.setCache(CACHE_KEY, result, 3e5);
39079
- return result;
39080
- } catch (error) {
39081
- logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
39082
- throw error;
39083
- }
39084
- }
39085
- async getPosition(supportedPosition) {
39086
- const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
39087
- const cached = this.getCache(CACHE_KEY);
39088
- if (cached) {
39089
- return cached;
39090
- }
39091
- try {
39092
- const vault = new Contract14({
39093
- abi: universal_vault_abi_default,
39094
- address: this.config.strategyVault.address,
39095
- providerOrAccount: this.config.networkConfig.provider
39096
- });
39097
- const owner = this._positionOwner();
39098
- const decimals = supportedPosition.asset.decimals;
39099
- const shares = await vault.balance_of(owner.address);
39100
- const shareU256 = uint25619.bnToUint256(shares);
39101
- const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
39102
- const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
39103
- let pending = Web3Number.fromWei("0", decimals);
39104
- try {
39105
- const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
39106
- pending = Web3Number.fromWei(dueRaw.toString(), decimals);
39107
- } catch (e) {
39108
- logger.warn(
39109
- `${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
39110
- );
39111
- }
39112
- const total = liquid.plus(pending);
39113
- const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
39114
- const result = {
39115
- amount: total,
39116
- remarks
39117
- };
39118
- this.setCache(CACHE_KEY, result, 6e4);
39119
- return result;
39120
- } catch (error) {
39121
- logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
39122
- throw error;
39123
- }
39124
- }
39125
- async maxDeposit(amount) {
39126
- const baseToken = this.config.baseToken;
39127
- if (!amount) {
39128
- return {
39129
- tokenInfo: baseToken,
39130
- amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
39131
- usdValue: 1e27,
39132
- remarks: "Max deposit (unbounded placeholder)",
39133
- apy: await this.getAPY({ asset: baseToken, isDebt: false }),
39134
- protocol: this.protocol
39135
- };
39136
- }
39137
- const usdValue = await this.getUSDValue(baseToken, amount);
39138
- return {
39139
- tokenInfo: baseToken,
39140
- amount,
39141
- usdValue,
39142
- remarks: "Deposit amount",
39143
- apy: await this.getAPY({ asset: baseToken, isDebt: false }),
39144
- protocol: this.protocol
39145
- };
39146
- }
39147
- async maxWithdraw() {
39148
- const baseToken = this.config.baseToken;
39149
- const current = await this.getPosition({ asset: baseToken, isDebt: false });
39150
- const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
39151
- const usdValue = await this.getUSDValue(baseToken, pos.amount);
39152
- return {
39153
- tokenInfo: baseToken,
39154
- amount: pos.amount,
39155
- usdValue,
39156
- remarks: "Max withdraw (liquid + pending redemption, underlying units)",
39157
- apy: await this.getAPY({ asset: baseToken, isDebt: false }),
39158
- protocol: this.protocol
39159
- };
39160
- }
39161
- _getDepositLeaf() {
39162
- const baseToken = this.config.baseToken;
39163
- const strategyVault = this.config.strategyVault;
39164
- const receiver = this.config.vaultAllocator;
39165
- return [
39057
+ // src/data/redeem-request-nft.abi.json
39058
+ var redeem_request_nft_abi_default = [
39059
+ {
39060
+ type: "impl",
39061
+ name: "RedeemRequestImpl",
39062
+ interface_name: "vault::redeem_request::interface::IRedeemRequest"
39063
+ },
39064
+ {
39065
+ type: "struct",
39066
+ name: "core::integer::u256",
39067
+ members: [
39166
39068
  {
39167
- target: baseToken.address,
39168
- method: "approve",
39169
- packedArguments: [strategyVault.toBigInt()],
39170
- sanitizer: SIMPLE_SANITIZER,
39171
- id: this._depositApproveProofReadableId()
39069
+ name: "low",
39070
+ type: "core::integer::u128"
39172
39071
  },
39173
39072
  {
39174
- target: strategyVault,
39175
- method: "deposit",
39176
- packedArguments: [receiver.toBigInt()],
39177
- sanitizer: SIMPLE_SANITIZER,
39178
- id: this._depositCallProofReadableId()
39179
- }
39180
- ];
39181
- }
39182
- _getWithdrawLeaf() {
39183
- const strategyVault = this.config.strategyVault;
39184
- const recv = this.config.vaultAllocator;
39185
- const owner = this.config.vaultAllocator;
39186
- return [
39187
- {
39188
- target: strategyVault,
39189
- method: "withdraw",
39190
- packedArguments: [recv.toBigInt(), owner.toBigInt()],
39191
- sanitizer: SIMPLE_SANITIZER,
39192
- id: this._withdrawCallProofReadableId()
39073
+ name: "high",
39074
+ type: "core::integer::u128"
39193
39075
  }
39194
- ];
39195
- }
39196
- getDepositAdapter() {
39197
- const leafConfigs = this._getDepositLeaf();
39198
- const leaves = leafConfigs.map((config) => {
39199
- const { target, method, packedArguments, sanitizer, id } = config;
39200
- return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
39201
- });
39202
- return { leaves, callConstructor: this.getDepositCall.bind(this) };
39203
- }
39204
- getWithdrawAdapter() {
39205
- const leafConfigs = this._getWithdrawLeaf();
39206
- const leaves = leafConfigs.map((config) => {
39207
- const { target, method, packedArguments, sanitizer, id } = config;
39208
- return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
39209
- });
39210
- return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
39211
- }
39212
- async getDepositCall(params) {
39213
- const baseToken = this.config.baseToken;
39214
- const strategyVault = this.config.strategyVault;
39215
- const amount = params.amount;
39216
- const uint256Amount = uint25619.bnToUint256(amount.toWei());
39217
- const receiver = this.config.vaultAllocator;
39218
- return [
39076
+ ]
39077
+ },
39078
+ {
39079
+ type: "struct",
39080
+ name: "vault::redeem_request::interface::RedeemRequestInfo",
39081
+ members: [
39219
39082
  {
39220
- proofReadableId: this._depositApproveProofReadableId(),
39221
- sanitizer: SIMPLE_SANITIZER,
39222
- call: {
39223
- contractAddress: baseToken.address,
39224
- selector: hash11.getSelectorFromName("approve"),
39225
- calldata: [
39226
- strategyVault.toBigInt(),
39227
- toBigInt(uint256Amount.low.toString()),
39228
- toBigInt(uint256Amount.high.toString())
39229
- ]
39230
- }
39083
+ name: "epoch",
39084
+ type: "core::integer::u256"
39231
39085
  },
39232
39086
  {
39233
- proofReadableId: this._depositCallProofReadableId(),
39087
+ name: "nominal",
39088
+ type: "core::integer::u256"
39089
+ }
39090
+ ]
39091
+ },
39092
+ {
39093
+ type: "interface",
39094
+ name: "vault::redeem_request::interface::IRedeemRequest",
39095
+ items: [
39096
+ {
39097
+ type: "function",
39098
+ name: "vault",
39099
+ inputs: [],
39100
+ outputs: [
39101
+ {
39102
+ type: "core::starknet::contract_address::ContractAddress"
39103
+ }
39104
+ ],
39105
+ state_mutability: "view"
39106
+ },
39107
+ {
39108
+ type: "function",
39109
+ name: "id_to_info",
39110
+ inputs: [
39111
+ {
39112
+ name: "id",
39113
+ type: "core::integer::u256"
39114
+ }
39115
+ ],
39116
+ outputs: [
39117
+ {
39118
+ type: "vault::redeem_request::interface::RedeemRequestInfo"
39119
+ }
39120
+ ],
39121
+ state_mutability: "view"
39122
+ },
39123
+ {
39124
+ type: "function",
39125
+ name: "id_len",
39126
+ inputs: [],
39127
+ outputs: [
39128
+ {
39129
+ type: "core::integer::u256"
39130
+ }
39131
+ ],
39132
+ state_mutability: "view"
39133
+ },
39134
+ {
39135
+ type: "function",
39136
+ name: "mint",
39137
+ inputs: [
39138
+ {
39139
+ name: "to",
39140
+ type: "core::starknet::contract_address::ContractAddress"
39141
+ },
39142
+ {
39143
+ name: "redeem_request_info",
39144
+ type: "vault::redeem_request::interface::RedeemRequestInfo"
39145
+ }
39146
+ ],
39147
+ outputs: [
39148
+ {
39149
+ type: "core::integer::u256"
39150
+ }
39151
+ ],
39152
+ state_mutability: "external"
39153
+ },
39154
+ {
39155
+ type: "function",
39156
+ name: "burn",
39157
+ inputs: [
39158
+ {
39159
+ name: "id",
39160
+ type: "core::integer::u256"
39161
+ }
39162
+ ],
39163
+ outputs: [],
39164
+ state_mutability: "external"
39165
+ }
39166
+ ]
39167
+ },
39168
+ {
39169
+ type: "impl",
39170
+ name: "UpgradeableImpl",
39171
+ interface_name: "openzeppelin_interfaces::upgrades::IUpgradeable"
39172
+ },
39173
+ {
39174
+ type: "interface",
39175
+ name: "openzeppelin_interfaces::upgrades::IUpgradeable",
39176
+ items: [
39177
+ {
39178
+ type: "function",
39179
+ name: "upgrade",
39180
+ inputs: [
39181
+ {
39182
+ name: "new_class_hash",
39183
+ type: "core::starknet::class_hash::ClassHash"
39184
+ }
39185
+ ],
39186
+ outputs: [],
39187
+ state_mutability: "external"
39188
+ }
39189
+ ]
39190
+ },
39191
+ {
39192
+ type: "impl",
39193
+ name: "ERC721MixinImpl",
39194
+ interface_name: "openzeppelin_interfaces::token::erc721::ERC721ABI"
39195
+ },
39196
+ {
39197
+ type: "struct",
39198
+ name: "core::array::Span::<core::felt252>",
39199
+ members: [
39200
+ {
39201
+ name: "snapshot",
39202
+ type: "@core::array::Array::<core::felt252>"
39203
+ }
39204
+ ]
39205
+ },
39206
+ {
39207
+ type: "enum",
39208
+ name: "core::bool",
39209
+ variants: [
39210
+ {
39211
+ name: "False",
39212
+ type: "()"
39213
+ },
39214
+ {
39215
+ name: "True",
39216
+ type: "()"
39217
+ }
39218
+ ]
39219
+ },
39220
+ {
39221
+ type: "struct",
39222
+ name: "core::byte_array::ByteArray",
39223
+ members: [
39224
+ {
39225
+ name: "data",
39226
+ type: "core::array::Array::<core::bytes_31::bytes31>"
39227
+ },
39228
+ {
39229
+ name: "pending_word",
39230
+ type: "core::felt252"
39231
+ },
39232
+ {
39233
+ name: "pending_word_len",
39234
+ type: "core::integer::u32"
39235
+ }
39236
+ ]
39237
+ },
39238
+ {
39239
+ type: "interface",
39240
+ name: "openzeppelin_interfaces::token::erc721::ERC721ABI",
39241
+ items: [
39242
+ {
39243
+ type: "function",
39244
+ name: "balance_of",
39245
+ inputs: [
39246
+ {
39247
+ name: "account",
39248
+ type: "core::starknet::contract_address::ContractAddress"
39249
+ }
39250
+ ],
39251
+ outputs: [
39252
+ {
39253
+ type: "core::integer::u256"
39254
+ }
39255
+ ],
39256
+ state_mutability: "view"
39257
+ },
39258
+ {
39259
+ type: "function",
39260
+ name: "owner_of",
39261
+ inputs: [
39262
+ {
39263
+ name: "token_id",
39264
+ type: "core::integer::u256"
39265
+ }
39266
+ ],
39267
+ outputs: [
39268
+ {
39269
+ type: "core::starknet::contract_address::ContractAddress"
39270
+ }
39271
+ ],
39272
+ state_mutability: "view"
39273
+ },
39274
+ {
39275
+ type: "function",
39276
+ name: "safe_transfer_from",
39277
+ inputs: [
39278
+ {
39279
+ name: "from",
39280
+ type: "core::starknet::contract_address::ContractAddress"
39281
+ },
39282
+ {
39283
+ name: "to",
39284
+ type: "core::starknet::contract_address::ContractAddress"
39285
+ },
39286
+ {
39287
+ name: "token_id",
39288
+ type: "core::integer::u256"
39289
+ },
39290
+ {
39291
+ name: "data",
39292
+ type: "core::array::Span::<core::felt252>"
39293
+ }
39294
+ ],
39295
+ outputs: [],
39296
+ state_mutability: "external"
39297
+ },
39298
+ {
39299
+ type: "function",
39300
+ name: "transfer_from",
39301
+ inputs: [
39302
+ {
39303
+ name: "from",
39304
+ type: "core::starknet::contract_address::ContractAddress"
39305
+ },
39306
+ {
39307
+ name: "to",
39308
+ type: "core::starknet::contract_address::ContractAddress"
39309
+ },
39310
+ {
39311
+ name: "token_id",
39312
+ type: "core::integer::u256"
39313
+ }
39314
+ ],
39315
+ outputs: [],
39316
+ state_mutability: "external"
39317
+ },
39318
+ {
39319
+ type: "function",
39320
+ name: "approve",
39321
+ inputs: [
39322
+ {
39323
+ name: "to",
39324
+ type: "core::starknet::contract_address::ContractAddress"
39325
+ },
39326
+ {
39327
+ name: "token_id",
39328
+ type: "core::integer::u256"
39329
+ }
39330
+ ],
39331
+ outputs: [],
39332
+ state_mutability: "external"
39333
+ },
39334
+ {
39335
+ type: "function",
39336
+ name: "set_approval_for_all",
39337
+ inputs: [
39338
+ {
39339
+ name: "operator",
39340
+ type: "core::starknet::contract_address::ContractAddress"
39341
+ },
39342
+ {
39343
+ name: "approved",
39344
+ type: "core::bool"
39345
+ }
39346
+ ],
39347
+ outputs: [],
39348
+ state_mutability: "external"
39349
+ },
39350
+ {
39351
+ type: "function",
39352
+ name: "get_approved",
39353
+ inputs: [
39354
+ {
39355
+ name: "token_id",
39356
+ type: "core::integer::u256"
39357
+ }
39358
+ ],
39359
+ outputs: [
39360
+ {
39361
+ type: "core::starknet::contract_address::ContractAddress"
39362
+ }
39363
+ ],
39364
+ state_mutability: "view"
39365
+ },
39366
+ {
39367
+ type: "function",
39368
+ name: "is_approved_for_all",
39369
+ inputs: [
39370
+ {
39371
+ name: "owner",
39372
+ type: "core::starknet::contract_address::ContractAddress"
39373
+ },
39374
+ {
39375
+ name: "operator",
39376
+ type: "core::starknet::contract_address::ContractAddress"
39377
+ }
39378
+ ],
39379
+ outputs: [
39380
+ {
39381
+ type: "core::bool"
39382
+ }
39383
+ ],
39384
+ state_mutability: "view"
39385
+ },
39386
+ {
39387
+ type: "function",
39388
+ name: "supports_interface",
39389
+ inputs: [
39390
+ {
39391
+ name: "interface_id",
39392
+ type: "core::felt252"
39393
+ }
39394
+ ],
39395
+ outputs: [
39396
+ {
39397
+ type: "core::bool"
39398
+ }
39399
+ ],
39400
+ state_mutability: "view"
39401
+ },
39402
+ {
39403
+ type: "function",
39404
+ name: "name",
39405
+ inputs: [],
39406
+ outputs: [
39407
+ {
39408
+ type: "core::byte_array::ByteArray"
39409
+ }
39410
+ ],
39411
+ state_mutability: "view"
39412
+ },
39413
+ {
39414
+ type: "function",
39415
+ name: "symbol",
39416
+ inputs: [],
39417
+ outputs: [
39418
+ {
39419
+ type: "core::byte_array::ByteArray"
39420
+ }
39421
+ ],
39422
+ state_mutability: "view"
39423
+ },
39424
+ {
39425
+ type: "function",
39426
+ name: "token_uri",
39427
+ inputs: [
39428
+ {
39429
+ name: "token_id",
39430
+ type: "core::integer::u256"
39431
+ }
39432
+ ],
39433
+ outputs: [
39434
+ {
39435
+ type: "core::byte_array::ByteArray"
39436
+ }
39437
+ ],
39438
+ state_mutability: "view"
39439
+ },
39440
+ {
39441
+ type: "function",
39442
+ name: "balanceOf",
39443
+ inputs: [
39444
+ {
39445
+ name: "account",
39446
+ type: "core::starknet::contract_address::ContractAddress"
39447
+ }
39448
+ ],
39449
+ outputs: [
39450
+ {
39451
+ type: "core::integer::u256"
39452
+ }
39453
+ ],
39454
+ state_mutability: "view"
39455
+ },
39456
+ {
39457
+ type: "function",
39458
+ name: "ownerOf",
39459
+ inputs: [
39460
+ {
39461
+ name: "tokenId",
39462
+ type: "core::integer::u256"
39463
+ }
39464
+ ],
39465
+ outputs: [
39466
+ {
39467
+ type: "core::starknet::contract_address::ContractAddress"
39468
+ }
39469
+ ],
39470
+ state_mutability: "view"
39471
+ },
39472
+ {
39473
+ type: "function",
39474
+ name: "safeTransferFrom",
39475
+ inputs: [
39476
+ {
39477
+ name: "from",
39478
+ type: "core::starknet::contract_address::ContractAddress"
39479
+ },
39480
+ {
39481
+ name: "to",
39482
+ type: "core::starknet::contract_address::ContractAddress"
39483
+ },
39484
+ {
39485
+ name: "tokenId",
39486
+ type: "core::integer::u256"
39487
+ },
39488
+ {
39489
+ name: "data",
39490
+ type: "core::array::Span::<core::felt252>"
39491
+ }
39492
+ ],
39493
+ outputs: [],
39494
+ state_mutability: "external"
39495
+ },
39496
+ {
39497
+ type: "function",
39498
+ name: "transferFrom",
39499
+ inputs: [
39500
+ {
39501
+ name: "from",
39502
+ type: "core::starknet::contract_address::ContractAddress"
39503
+ },
39504
+ {
39505
+ name: "to",
39506
+ type: "core::starknet::contract_address::ContractAddress"
39507
+ },
39508
+ {
39509
+ name: "tokenId",
39510
+ type: "core::integer::u256"
39511
+ }
39512
+ ],
39513
+ outputs: [],
39514
+ state_mutability: "external"
39515
+ },
39516
+ {
39517
+ type: "function",
39518
+ name: "setApprovalForAll",
39519
+ inputs: [
39520
+ {
39521
+ name: "operator",
39522
+ type: "core::starknet::contract_address::ContractAddress"
39523
+ },
39524
+ {
39525
+ name: "approved",
39526
+ type: "core::bool"
39527
+ }
39528
+ ],
39529
+ outputs: [],
39530
+ state_mutability: "external"
39531
+ },
39532
+ {
39533
+ type: "function",
39534
+ name: "getApproved",
39535
+ inputs: [
39536
+ {
39537
+ name: "tokenId",
39538
+ type: "core::integer::u256"
39539
+ }
39540
+ ],
39541
+ outputs: [
39542
+ {
39543
+ type: "core::starknet::contract_address::ContractAddress"
39544
+ }
39545
+ ],
39546
+ state_mutability: "view"
39547
+ },
39548
+ {
39549
+ type: "function",
39550
+ name: "isApprovedForAll",
39551
+ inputs: [
39552
+ {
39553
+ name: "owner",
39554
+ type: "core::starknet::contract_address::ContractAddress"
39555
+ },
39556
+ {
39557
+ name: "operator",
39558
+ type: "core::starknet::contract_address::ContractAddress"
39559
+ }
39560
+ ],
39561
+ outputs: [
39562
+ {
39563
+ type: "core::bool"
39564
+ }
39565
+ ],
39566
+ state_mutability: "view"
39567
+ },
39568
+ {
39569
+ type: "function",
39570
+ name: "tokenURI",
39571
+ inputs: [
39572
+ {
39573
+ name: "tokenId",
39574
+ type: "core::integer::u256"
39575
+ }
39576
+ ],
39577
+ outputs: [
39578
+ {
39579
+ type: "core::byte_array::ByteArray"
39580
+ }
39581
+ ],
39582
+ state_mutability: "view"
39583
+ }
39584
+ ]
39585
+ },
39586
+ {
39587
+ type: "impl",
39588
+ name: "ERC721EnumerableImpl",
39589
+ interface_name: "openzeppelin_interfaces::token::erc721::IERC721Enumerable"
39590
+ },
39591
+ {
39592
+ type: "interface",
39593
+ name: "openzeppelin_interfaces::token::erc721::IERC721Enumerable",
39594
+ items: [
39595
+ {
39596
+ type: "function",
39597
+ name: "total_supply",
39598
+ inputs: [],
39599
+ outputs: [
39600
+ {
39601
+ type: "core::integer::u256"
39602
+ }
39603
+ ],
39604
+ state_mutability: "view"
39605
+ },
39606
+ {
39607
+ type: "function",
39608
+ name: "token_by_index",
39609
+ inputs: [
39610
+ {
39611
+ name: "index",
39612
+ type: "core::integer::u256"
39613
+ }
39614
+ ],
39615
+ outputs: [
39616
+ {
39617
+ type: "core::integer::u256"
39618
+ }
39619
+ ],
39620
+ state_mutability: "view"
39621
+ },
39622
+ {
39623
+ type: "function",
39624
+ name: "token_of_owner_by_index",
39625
+ inputs: [
39626
+ {
39627
+ name: "owner",
39628
+ type: "core::starknet::contract_address::ContractAddress"
39629
+ },
39630
+ {
39631
+ name: "index",
39632
+ type: "core::integer::u256"
39633
+ }
39634
+ ],
39635
+ outputs: [
39636
+ {
39637
+ type: "core::integer::u256"
39638
+ }
39639
+ ],
39640
+ state_mutability: "view"
39641
+ }
39642
+ ]
39643
+ },
39644
+ {
39645
+ type: "constructor",
39646
+ name: "constructor",
39647
+ inputs: [
39648
+ {
39649
+ name: "owner",
39650
+ type: "core::starknet::contract_address::ContractAddress"
39651
+ },
39652
+ {
39653
+ name: "vault",
39654
+ type: "core::starknet::contract_address::ContractAddress"
39655
+ }
39656
+ ]
39657
+ },
39658
+ {
39659
+ type: "event",
39660
+ name: "openzeppelin_token::erc721::erc721::ERC721Component::Transfer",
39661
+ kind: "struct",
39662
+ members: [
39663
+ {
39664
+ name: "from",
39665
+ type: "core::starknet::contract_address::ContractAddress",
39666
+ kind: "key"
39667
+ },
39668
+ {
39669
+ name: "to",
39670
+ type: "core::starknet::contract_address::ContractAddress",
39671
+ kind: "key"
39672
+ },
39673
+ {
39674
+ name: "token_id",
39675
+ type: "core::integer::u256",
39676
+ kind: "key"
39677
+ }
39678
+ ]
39679
+ },
39680
+ {
39681
+ type: "event",
39682
+ name: "openzeppelin_token::erc721::erc721::ERC721Component::Approval",
39683
+ kind: "struct",
39684
+ members: [
39685
+ {
39686
+ name: "owner",
39687
+ type: "core::starknet::contract_address::ContractAddress",
39688
+ kind: "key"
39689
+ },
39690
+ {
39691
+ name: "approved",
39692
+ type: "core::starknet::contract_address::ContractAddress",
39693
+ kind: "key"
39694
+ },
39695
+ {
39696
+ name: "token_id",
39697
+ type: "core::integer::u256",
39698
+ kind: "key"
39699
+ }
39700
+ ]
39701
+ },
39702
+ {
39703
+ type: "event",
39704
+ name: "openzeppelin_token::erc721::erc721::ERC721Component::ApprovalForAll",
39705
+ kind: "struct",
39706
+ members: [
39707
+ {
39708
+ name: "owner",
39709
+ type: "core::starknet::contract_address::ContractAddress",
39710
+ kind: "key"
39711
+ },
39712
+ {
39713
+ name: "operator",
39714
+ type: "core::starknet::contract_address::ContractAddress",
39715
+ kind: "key"
39716
+ },
39717
+ {
39718
+ name: "approved",
39719
+ type: "core::bool",
39720
+ kind: "data"
39721
+ }
39722
+ ]
39723
+ },
39724
+ {
39725
+ type: "event",
39726
+ name: "openzeppelin_token::erc721::erc721::ERC721Component::Event",
39727
+ kind: "enum",
39728
+ variants: [
39729
+ {
39730
+ name: "Transfer",
39731
+ type: "openzeppelin_token::erc721::erc721::ERC721Component::Transfer",
39732
+ kind: "nested"
39733
+ },
39734
+ {
39735
+ name: "Approval",
39736
+ type: "openzeppelin_token::erc721::erc721::ERC721Component::Approval",
39737
+ kind: "nested"
39738
+ },
39739
+ {
39740
+ name: "ApprovalForAll",
39741
+ type: "openzeppelin_token::erc721::erc721::ERC721Component::ApprovalForAll",
39742
+ kind: "nested"
39743
+ }
39744
+ ]
39745
+ },
39746
+ {
39747
+ type: "event",
39748
+ name: "openzeppelin_token::erc721::extensions::erc721_enumerable::erc721_enumerable::ERC721EnumerableComponent::Event",
39749
+ kind: "enum",
39750
+ variants: []
39751
+ },
39752
+ {
39753
+ type: "event",
39754
+ name: "openzeppelin_introspection::src5::SRC5Component::Event",
39755
+ kind: "enum",
39756
+ variants: []
39757
+ },
39758
+ {
39759
+ type: "event",
39760
+ name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
39761
+ kind: "struct",
39762
+ members: [
39763
+ {
39764
+ name: "class_hash",
39765
+ type: "core::starknet::class_hash::ClassHash",
39766
+ kind: "data"
39767
+ }
39768
+ ]
39769
+ },
39770
+ {
39771
+ type: "event",
39772
+ name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
39773
+ kind: "enum",
39774
+ variants: [
39775
+ {
39776
+ name: "Upgraded",
39777
+ type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
39778
+ kind: "nested"
39779
+ }
39780
+ ]
39781
+ },
39782
+ {
39783
+ type: "event",
39784
+ name: "vault::redeem_request::redeem_request::RedeemRequest::Event",
39785
+ kind: "enum",
39786
+ variants: [
39787
+ {
39788
+ name: "ERC721Event",
39789
+ type: "openzeppelin_token::erc721::erc721::ERC721Component::Event",
39790
+ kind: "flat"
39791
+ },
39792
+ {
39793
+ name: "ERC721EnumerableEvent",
39794
+ type: "openzeppelin_token::erc721::extensions::erc721_enumerable::erc721_enumerable::ERC721EnumerableComponent::Event",
39795
+ kind: "flat"
39796
+ },
39797
+ {
39798
+ name: "SRC5Event",
39799
+ type: "openzeppelin_introspection::src5::SRC5Component::Event",
39800
+ kind: "flat"
39801
+ },
39802
+ {
39803
+ name: "UpgradeableEvent",
39804
+ type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
39805
+ kind: "flat"
39806
+ }
39807
+ ]
39808
+ }
39809
+ ];
39810
+
39811
+ // src/strategies/universal-adapters/svk-troves-adapter.ts
39812
+ var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
39813
+ function parseTrovesApyField(raw) {
39814
+ if (typeof raw === "number" && Number.isFinite(raw)) {
39815
+ return raw;
39816
+ }
39817
+ if (typeof raw === "string") {
39818
+ const n = Number.parseFloat(raw);
39819
+ if (Number.isFinite(n)) {
39820
+ return n;
39821
+ }
39822
+ }
39823
+ return 0;
39824
+ }
39825
+ var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
39826
+ constructor(config) {
39827
+ super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
39828
+ this.config = config;
39829
+ }
39830
+ /** Owner used for share balance + `due_assets_from_owner`. */
39831
+ _positionOwner() {
39832
+ return this.config.positionOwner ?? this.config.vaultAllocator;
39833
+ }
39834
+ /**
39835
+ * Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
39836
+ * `strategyVault` address so multiple SVK adapters in one tree stay distinct.
39837
+ */
39838
+ _proofSuffix() {
39839
+ return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
39840
+ }
39841
+ _depositApproveProofReadableId() {
39842
+ return `appr_dep_svk_${this._proofSuffix()}`;
39843
+ }
39844
+ _depositCallProofReadableId() {
39845
+ return `dep_svk_${this._proofSuffix()}`;
39846
+ }
39847
+ _withdrawCallProofReadableId() {
39848
+ return `wtdrw_svk_${this._proofSuffix()}`;
39849
+ }
39850
+ async getAPY(supportedPosition) {
39851
+ const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
39852
+ const cached = this.getCache(CACHE_KEY);
39853
+ if (cached) {
39854
+ return cached;
39855
+ }
39856
+ const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
39857
+ try {
39858
+ const res = await fetch(url);
39859
+ if (!res.ok) {
39860
+ logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
39861
+ const fallback = { apy: 0, type: "base" /* BASE */ };
39862
+ this.setCache(CACHE_KEY, fallback, 3e5);
39863
+ return fallback;
39864
+ }
39865
+ const body = await res.json();
39866
+ const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
39867
+ if (!row) {
39868
+ logger.warn(
39869
+ `${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
39870
+ );
39871
+ const fallback = { apy: 0, type: "base" /* BASE */ };
39872
+ this.setCache(CACHE_KEY, fallback, 3e5);
39873
+ return fallback;
39874
+ }
39875
+ const apy = parseTrovesApyField(row.apy);
39876
+ const result = { apy, type: "base" /* BASE */ };
39877
+ this.setCache(CACHE_KEY, result, 3e5);
39878
+ return result;
39879
+ } catch (error) {
39880
+ logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
39881
+ throw error;
39882
+ }
39883
+ }
39884
+ async getPosition(supportedPosition) {
39885
+ const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
39886
+ const cached = this.getCache(CACHE_KEY);
39887
+ if (cached) {
39888
+ return cached;
39889
+ }
39890
+ try {
39891
+ const vault = new Contract14({
39892
+ abi: universal_vault_abi_default,
39893
+ address: this.config.strategyVault.address,
39894
+ providerOrAccount: this.config.networkConfig.provider
39895
+ });
39896
+ const owner = this._positionOwner();
39897
+ const decimals = supportedPosition.asset.decimals;
39898
+ const shares = await vault.balance_of(owner.address);
39899
+ const shareU256 = uint25619.bnToUint256(shares);
39900
+ const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
39901
+ const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
39902
+ let pending = Web3Number.fromWei("0", decimals);
39903
+ try {
39904
+ const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
39905
+ pending = Web3Number.fromWei(dueRaw.toString(), decimals);
39906
+ } catch (e) {
39907
+ logger.warn(
39908
+ `${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
39909
+ );
39910
+ }
39911
+ const total = liquid.plus(pending);
39912
+ const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
39913
+ const result = {
39914
+ amount: total,
39915
+ remarks
39916
+ };
39917
+ this.setCache(CACHE_KEY, result, 6e4);
39918
+ return result;
39919
+ } catch (error) {
39920
+ logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
39921
+ throw error;
39922
+ }
39923
+ }
39924
+ async getPendingAssetsFromOwner(owner = this._positionOwner(), decimals = this.config.baseToken.decimals) {
39925
+ const vault = new Contract14({
39926
+ abi: universal_vault_abi_default,
39927
+ address: this.config.strategyVault.address,
39928
+ providerOrAccount: this.config.networkConfig.provider
39929
+ });
39930
+ try {
39931
+ const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
39932
+ return Web3Number.fromWei(dueRaw.toString(), decimals);
39933
+ } catch (e) {
39934
+ logger.warn(
39935
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwner: due_assets_from_owner failed (treating as 0): ${e.message}`
39936
+ );
39937
+ return Web3Number.fromWei("0", decimals);
39938
+ }
39939
+ }
39940
+ /**
39941
+ * Get pending assets from owner by scanning redeem request NFTs.
39942
+ * This method iterates backwards through NFT IDs to find all pending redemptions for a specific owner.
39943
+ *
39944
+ * @param redeemRequestNFT - The redeem request NFT contract address
39945
+ * @param owner - The owner address to check for pending redemptions (defaults to positionOwner)
39946
+ * @param decimals - Token decimals for conversion (defaults to baseToken decimals)
39947
+ * @returns Total pending assets from all NFTs owned by the specified address
39948
+ */
39949
+ async getPendingAssetsFromOwnerNFTMethod(redeemRequestNFT, owner = this._positionOwner(), decimals = this.config.baseToken.decimals) {
39950
+ try {
39951
+ const nftContract = new Contract14({
39952
+ abi: redeem_request_nft_abi_default,
39953
+ address: redeemRequestNFT.address,
39954
+ providerOrAccount: this.config.networkConfig.provider
39955
+ });
39956
+ const idLenRaw = await nftContract.id_len();
39957
+ const latestId = BigInt(idLenRaw.toString());
39958
+ if (latestId === 0n) {
39959
+ logger.info(
39960
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: No NFTs minted yet`
39961
+ );
39962
+ return Web3Number.fromWei("0", decimals);
39963
+ }
39964
+ const matchingIds = [];
39965
+ let currentId = latestId - 1n;
39966
+ while (currentId >= 0n) {
39967
+ try {
39968
+ const idU256 = uint25619.bnToUint256(currentId);
39969
+ const ownerRaw = await nftContract.owner_of(idU256);
39970
+ const nftOwnerAddr = ContractAddr.from(ownerRaw.toString());
39971
+ if (nftOwnerAddr.eq(owner)) {
39972
+ matchingIds.push(currentId);
39973
+ logger.debug(
39974
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Found matching NFT ID ${currentId} for owner ${owner.address}`
39975
+ );
39976
+ }
39977
+ currentId--;
39978
+ } catch (e) {
39979
+ logger.info(
39980
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Reached last pending NFT at id ${currentId}`
39981
+ );
39982
+ break;
39983
+ }
39984
+ }
39985
+ if (matchingIds.length === 0) {
39986
+ logger.info(
39987
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: No matching NFTs found for owner ${owner.address}`
39988
+ );
39989
+ return Web3Number.fromWei("0", decimals);
39990
+ }
39991
+ let totalNominal = 0n;
39992
+ for (const nftId of matchingIds) {
39993
+ try {
39994
+ const idU256 = uint25619.bnToUint256(nftId);
39995
+ const infoRaw = await nftContract.id_to_info(idU256);
39996
+ const nominal = BigInt(infoRaw.nominal.toString());
39997
+ totalNominal += nominal;
39998
+ logger.debug(
39999
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: NFT ID ${nftId} has nominal ${nominal}`
40000
+ );
40001
+ } catch (e) {
40002
+ logger.warn(
40003
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Failed to get info for NFT ID ${nftId}: ${e.message}`
40004
+ );
40005
+ }
40006
+ }
40007
+ logger.info(
40008
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Found ${matchingIds.length} NFTs with total nominal ${totalNominal}`
40009
+ );
40010
+ return Web3Number.fromWei(totalNominal.toString(), decimals);
40011
+ } catch (error) {
40012
+ logger.error(
40013
+ `${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: ${error.message}`
40014
+ );
40015
+ return Web3Number.fromWei("0", decimals);
40016
+ }
40017
+ }
40018
+ async maxDeposit(amount) {
40019
+ const baseToken = this.config.baseToken;
40020
+ if (!amount) {
40021
+ return {
40022
+ tokenInfo: baseToken,
40023
+ amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
40024
+ usdValue: 1e27,
40025
+ remarks: "Max deposit (unbounded placeholder)",
40026
+ apy: await this.getAPY({ asset: baseToken, isDebt: false }),
40027
+ protocol: this.protocol
40028
+ };
40029
+ }
40030
+ const usdValue = await this.getUSDValue(baseToken, amount);
40031
+ return {
40032
+ tokenInfo: baseToken,
40033
+ amount,
40034
+ usdValue,
40035
+ remarks: "Deposit amount",
40036
+ apy: await this.getAPY({ asset: baseToken, isDebt: false }),
40037
+ protocol: this.protocol
40038
+ };
40039
+ }
40040
+ async maxWithdraw() {
40041
+ const baseToken = this.config.baseToken;
40042
+ const current = await this.getPosition({ asset: baseToken, isDebt: false });
40043
+ const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
40044
+ const usdValue = await this.getUSDValue(baseToken, pos.amount);
40045
+ return {
40046
+ tokenInfo: baseToken,
40047
+ amount: pos.amount,
40048
+ usdValue,
40049
+ remarks: "Max withdraw (liquid + pending redemption, underlying units)",
40050
+ apy: await this.getAPY({ asset: baseToken, isDebt: false }),
40051
+ protocol: this.protocol
40052
+ };
40053
+ }
40054
+ _getDepositLeaf() {
40055
+ const baseToken = this.config.baseToken;
40056
+ const strategyVault = this.config.strategyVault;
40057
+ const receiver = this.config.vaultAllocator;
40058
+ return [
40059
+ {
40060
+ target: baseToken.address,
40061
+ method: "approve",
40062
+ packedArguments: [strategyVault.toBigInt()],
40063
+ sanitizer: SIMPLE_SANITIZER,
40064
+ id: this._depositApproveProofReadableId()
40065
+ },
40066
+ {
40067
+ target: strategyVault,
40068
+ method: "deposit",
40069
+ packedArguments: [receiver.toBigInt()],
40070
+ sanitizer: SIMPLE_SANITIZER,
40071
+ id: this._depositCallProofReadableId()
40072
+ }
40073
+ ];
40074
+ }
40075
+ _getWithdrawLeaf() {
40076
+ const strategyVault = this.config.strategyVault;
40077
+ const recv = this.config.vaultAllocator;
40078
+ const owner = this.config.vaultAllocator;
40079
+ return [
40080
+ {
40081
+ target: strategyVault,
40082
+ method: "request_redeem",
40083
+ packedArguments: [recv.toBigInt(), owner.toBigInt()],
40084
+ sanitizer: SVK_SIMPLE_SANITIZER,
40085
+ id: this._withdrawCallProofReadableId()
40086
+ }
40087
+ ];
40088
+ }
40089
+ getDepositAdapter() {
40090
+ const leafConfigs = this._getDepositLeaf();
40091
+ const leaves = leafConfigs.map((config) => {
40092
+ const { target, method, packedArguments, sanitizer, id } = config;
40093
+ return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
40094
+ });
40095
+ return { leaves, callConstructor: this.getDepositCall.bind(this) };
40096
+ }
40097
+ getWithdrawAdapter() {
40098
+ const leafConfigs = this._getWithdrawLeaf();
40099
+ const leaves = leafConfigs.map((config) => {
40100
+ const { target, method, packedArguments, sanitizer, id } = config;
40101
+ return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
40102
+ });
40103
+ return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
40104
+ }
40105
+ async getDepositCall(params) {
40106
+ const baseToken = this.config.baseToken;
40107
+ const strategyVault = this.config.strategyVault;
40108
+ const amount = params.amount;
40109
+ const uint256Amount = uint25619.bnToUint256(amount.toWei());
40110
+ const receiver = this.config.vaultAllocator;
40111
+ return [
40112
+ {
40113
+ proofReadableId: this._depositApproveProofReadableId(),
40114
+ sanitizer: SIMPLE_SANITIZER,
40115
+ call: {
40116
+ contractAddress: baseToken.address,
40117
+ selector: hash11.getSelectorFromName("approve"),
40118
+ calldata: [
40119
+ strategyVault.toBigInt(),
40120
+ toBigInt(uint256Amount.low.toString()),
40121
+ toBigInt(uint256Amount.high.toString())
40122
+ ]
40123
+ }
40124
+ },
40125
+ {
40126
+ proofReadableId: this._depositCallProofReadableId(),
39234
40127
  sanitizer: SIMPLE_SANITIZER,
39235
40128
  call: {
39236
40129
  contractAddress: strategyVault,
@@ -39250,16 +40143,23 @@ var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
39250
40143
  const uint256Amount = uint25619.bnToUint256(amount.toWei());
39251
40144
  const recv = this.config.vaultAllocator;
39252
40145
  const owner = this.config.vaultAllocator;
40146
+ const vault = new Contract14({
40147
+ abi: universal_vault_abi_default,
40148
+ address: strategyVault.address,
40149
+ providerOrAccount: this.config.networkConfig.provider
40150
+ });
40151
+ const sharesRaw = await vault.convert_to_shares(uint256Amount);
40152
+ const sharesU256 = uint25619.bnToUint256(sharesRaw.toString());
39253
40153
  return [
39254
40154
  {
39255
40155
  proofReadableId: this._withdrawCallProofReadableId(),
39256
- sanitizer: SIMPLE_SANITIZER,
40156
+ sanitizer: SVK_SIMPLE_SANITIZER,
39257
40157
  call: {
39258
40158
  contractAddress: strategyVault,
39259
- selector: hash11.getSelectorFromName("withdraw"),
40159
+ selector: hash11.getSelectorFromName("request_redeem"),
39260
40160
  calldata: [
39261
- toBigInt(uint256Amount.low.toString()),
39262
- toBigInt(uint256Amount.high.toString()),
40161
+ toBigInt(sharesU256.low.toString()),
40162
+ toBigInt(sharesU256.high.toString()),
39263
40163
  recv.toBigInt(),
39264
40164
  owner.toBigInt()
39265
40165
  ]
@@ -41044,9 +41944,9 @@ var SVKStrategy = class extends BaseStrategy {
41044
41944
  * Builds a manage call from an adapter's proof tree.
41045
41945
  * DRY helper for the repeated getProofs → getManageCall pattern.
41046
41946
  */
41047
- async buildManageCallFromAdapter(adapter, isDeposit, amount) {
41947
+ async buildManageCallFromAdapter(adapter, isDeposit, amount, additionalParams) {
41048
41948
  const proofsInfo = adapter.getProofs(isDeposit, this.getMerkleTree());
41049
- const manageCalls = await proofsInfo.callConstructor({ amount });
41949
+ const manageCalls = await proofsInfo.callConstructor({ amount, ...additionalParams });
41050
41950
  return this.getManageCall(
41051
41951
  this.getProofGroupsForManageCalls(manageCalls),
41052
41952
  manageCalls
@@ -42148,95 +43048,615 @@ function createHyperLSTSettings(lstSymbol, underlyingSymbol) {
42148
43048
  ] }),
42149
43049
  type: "info"
42150
43050
  },
42151
- {
42152
- tab: "deposit",
42153
- text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
42154
- type: "info"
42155
- }
42156
- ]
42157
- };
42158
- }
42159
- var HYPER_LST_SECURITY = {
42160
- auditStatus: "Audited" /* AUDITED */,
42161
- sourceCode: {
42162
- type: "Closed Source" /* CLOSED_SOURCE */,
42163
- contractLink: "https://github.com/trovesfi/troves-contracts"
42164
- },
42165
- accessControl: {
42166
- type: "Standard Account" /* STANDARD_ACCOUNT */,
42167
- addresses: [ContractAddr.from("0x0")],
42168
- timeLock: "2 Days"
43051
+ {
43052
+ tab: "deposit",
43053
+ text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
43054
+ type: "info"
43055
+ }
43056
+ ]
43057
+ };
43058
+ }
43059
+ var HYPER_LST_SECURITY = {
43060
+ auditStatus: "Audited" /* AUDITED */,
43061
+ sourceCode: {
43062
+ type: "Closed Source" /* CLOSED_SOURCE */,
43063
+ contractLink: "https://github.com/trovesfi/troves-contracts"
43064
+ },
43065
+ accessControl: {
43066
+ type: "Standard Account" /* STANDARD_ACCOUNT */,
43067
+ addresses: [ContractAddr.from("0x0")],
43068
+ timeLock: "2 Days"
43069
+ }
43070
+ };
43071
+ var HYPER_LST_REDEMPTION_INFO = {
43072
+ instantWithdrawalVault: "No" /* NO */,
43073
+ redemptionsInfo: [
43074
+ {
43075
+ title: "Typical Duration",
43076
+ description: "1-2 hours"
43077
+ }
43078
+ ],
43079
+ alerts: [
43080
+ {
43081
+ type: "info",
43082
+ text: "In cases of low liquidity, high slippages, the redemptions can take longer time. Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
43083
+ tab: "withdraw"
43084
+ }
43085
+ ]
43086
+ };
43087
+ function getStrategySettings(lstSymbol, underlyingSymbol, settings, isPreview = false, isLST) {
43088
+ return {
43089
+ id: `hyper_${lstSymbol.toLowerCase()}`,
43090
+ name: `Hyper ${lstSymbol}`,
43091
+ description: getDescription2(lstSymbol, underlyingSymbol),
43092
+ address: settings.vaultAddress,
43093
+ launchBlock: 0,
43094
+ type: "Other",
43095
+ vaultType: {
43096
+ type: "Looping" /* LOOPING */,
43097
+ description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`
43098
+ },
43099
+ depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === lstSymbol)],
43100
+ additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, settings, lstSymbol === "xSTRK" ? VesuPools.Re7xSTRK : VesuPools.Re7xBTC),
43101
+ risk: {
43102
+ riskFactor: _riskFactor4,
43103
+ netRisk: _riskFactor4.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor4.reduce((acc, curr) => acc + curr.weight, 0),
43104
+ notARisks: getNoRiskTags(_riskFactor4)
43105
+ },
43106
+ auditUrl: AUDIT_URL4,
43107
+ protocols: [Protocols.ENDUR, Protocols.VESU],
43108
+ curator: {
43109
+ name: "Unwrap Labs",
43110
+ logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
43111
+ },
43112
+ settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
43113
+ contractDetails: getContractDetails(settings),
43114
+ faqs: getFAQs2(lstSymbol, underlyingSymbol, isLST),
43115
+ investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
43116
+ isPreview,
43117
+ apyMethodology: "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.",
43118
+ realizedAPYMethodology: "The realizedAPY is based on past 14 days performance by the vault",
43119
+ tags: lstSymbol.includes("BTC") ? ["BTC" /* BTC */, "Maxx" /* LEVERED */] : ["Maxx" /* LEVERED */],
43120
+ security: HYPER_LST_SECURITY,
43121
+ redemptionInfo: HYPER_LST_REDEMPTION_INFO,
43122
+ usualTimeToEarnings: "2 weeks",
43123
+ usualTimeToEarningsDescription: "Strategy returns depend on LST price on DEXes. Even though the true price of LST on Endur increases continuously, the DEX price may lag sometimes, and historically is seen to rebase at least once every 2 hours. This is when you realise your earnings.",
43124
+ points: lstSymbol === "xSTRK" ? [{
43125
+ multiplier: 4,
43126
+ logo: "https://endur.fi/favicon.ico",
43127
+ toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi."
43128
+ }] : void 0
43129
+ };
43130
+ }
43131
+ var HyperLSTStrategies = [
43132
+ getStrategySettings("xSTRK", "STRK", hyperxSTRK, false, true),
43133
+ getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false, false),
43134
+ getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false, false),
43135
+ getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false, false),
43136
+ getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false, false),
43137
+ getStrategySettings("mRe7BTC", "mRe7BTC", hypermRe7BTC, false, false),
43138
+ getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
43139
+ ];
43140
+
43141
+ // src/strategies/usdc-boosted-strategy.tsx
43142
+ import { uint256 as uint25623 } from "starknet";
43143
+ var USDCBoostedStrategy = class _USDCBoostedStrategy extends SVKStrategy {
43144
+ constructor(config, pricer, metadata) {
43145
+ super(config, pricer, metadata);
43146
+ this.metadata.additionalInfo.adapters.forEach((adapter) => {
43147
+ adapter.adapter.config.networkConfig = this.config;
43148
+ adapter.adapter.config.pricer = this.pricer;
43149
+ if (adapter.adapter._vesuAdapter) {
43150
+ adapter.adapter._vesuAdapter.networkConfig = this.config;
43151
+ adapter.adapter._vesuAdapter.pricer = this.pricer;
43152
+ }
43153
+ });
43154
+ }
43155
+ getTag() {
43156
+ return `${_USDCBoostedStrategy.name}:${this.metadata.name}`;
43157
+ }
43158
+ getAdapterById(id) {
43159
+ const entry = this.metadata.additionalInfo.adapters.find(
43160
+ (a) => a.id === id
43161
+ );
43162
+ if (!entry) {
43163
+ throw new Error(
43164
+ `${this.getTag()}::getAdapterById: adapter not found for id "${id}"`
43165
+ );
43166
+ }
43167
+ return entry.adapter;
43168
+ }
43169
+ async getVesuModifyPositionCall(params) {
43170
+ logger.verbose(
43171
+ `${this.getTag()}::getVesuModifyPositionCall isDeposit=${params.isDeposit}, amount=${params.leg1DepositAmount}, debtAmount=${params.debtAmount?.toNumber()}`
43172
+ );
43173
+ return this.buildManageCallFromAdapter(
43174
+ this.getAdapterById("vesu_usdc_strk"),
43175
+ params.isDeposit,
43176
+ params.leg1DepositAmount,
43177
+ params.debtAmount ? { debtAmount: params.debtAmount } : void 0
43178
+ );
43179
+ }
43180
+ async getVesuPositions() {
43181
+ const positions = await this.getAdapterById(
43182
+ "vesu_usdc_strk"
43183
+ ).getPositions();
43184
+ return positions.map((p) => ({
43185
+ amount: p.amount,
43186
+ usdValue: p.usdValue,
43187
+ remarks: p.remarks ?? "",
43188
+ token: p.tokenInfo,
43189
+ protocol: p.protocol
43190
+ }));
43191
+ }
43192
+ async getVesuHealthFactor(blockNumber = "latest") {
43193
+ const vesuAdapter = this.getAdapterById("vesu_usdc_strk");
43194
+ return await vesuAdapter._vesuAdapter.getHealthFactor(blockNumber);
43195
+ }
43196
+ // TODO: will have to still modify for instant withdrawals as of now
43197
+ async getModifyHyperPositionCall(params) {
43198
+ logger.verbose(
43199
+ `${this.getTag()}::getModifyHyperPositionCall isDeposit=${params.isDeposit}, amount=${params.amount}`
43200
+ );
43201
+ return this.buildManageCallFromAdapter(
43202
+ this.getAdapterById("hyper_xstrk"),
43203
+ params.isDeposit,
43204
+ params.amount
43205
+ );
43206
+ }
43207
+ async getAvnuSwapCall(params) {
43208
+ logger.verbose(
43209
+ `${this.getTag()}::getAvnuSwapCall isDeposit=${params.isDeposit}, amount=${params.amount}`
43210
+ );
43211
+ return this.buildManageCallFromAdapter(
43212
+ this.getAdapterById("avnu_strk_xstrk"),
43213
+ params.isDeposit,
43214
+ params.amount
43215
+ );
43216
+ }
43217
+ /**
43218
+ * Returns the USDC balance sitting idle inside the vault contract itself.
43219
+ * This balance can offset the required liquidity during withdrawal processing.
43220
+ */
43221
+ async getUnusedBalanceVault() {
43222
+ const collateralToken = this.metadata.additionalInfo.collateralToken;
43223
+ return new ERC20(this.config).balanceOf(
43224
+ collateralToken.address,
43225
+ this.metadata.additionalInfo.vaultAddress,
43226
+ collateralToken.decimals
43227
+ );
43228
+ }
43229
+ /**
43230
+ * Returns the current STRK balance sitting unused in the vault allocator.
43231
+ * This covers STRK from prior borrow cycles that hasn't been swapped yet.
43232
+ */
43233
+ // Technically we can use this or we can even use the avnu-adapter to get the unused debt
43234
+ async getUnusedDebt() {
43235
+ const debtToken = this.metadata.additionalInfo.debtToken;
43236
+ return new ERC20(this.config).balanceOf(
43237
+ debtToken.address,
43238
+ this.metadata.additionalInfo.vaultAllocator,
43239
+ debtToken.decimals
43240
+ );
43241
+ }
43242
+ /**
43243
+ * Returns the xSTRK balance sitting in the vault allocator.
43244
+ * This is non-zero when the previous cycle's request_redeem on the HyperPosition
43245
+ * has been settled — the redeemed xSTRK lands here and is ready to be swapped.
43246
+ */
43247
+ async getxSTRKInVault() {
43248
+ const xstrkToken = Global.getDefaultTokens().find(
43249
+ (t) => t.symbol === "xSTRK"
43250
+ );
43251
+ if (!xstrkToken) {
43252
+ throw new Error(`${this.getTag()}:: xSTRK token not found`);
43253
+ }
43254
+ return new ERC20(this.config).balanceOf(
43255
+ xstrkToken.address.address,
43256
+ this.metadata.additionalInfo.vaultAllocator,
43257
+ xstrkToken.decimals
43258
+ );
43259
+ }
43260
+ /**
43261
+ * Simulates depositing `depositAmount` USDC on Vesu and returns the
43262
+ * incremental STRK that would be borrowed. Needed to size the AVNU swap
43263
+ * call that is batched together with the Vesu call in the same transaction.
43264
+ */
43265
+ async computeVesuDepositBorrowAmount(depositAmount) {
43266
+ return this.getAdapterById(
43267
+ "vesu_usdc_strk"
43268
+ ).getExpectedDepositDebtDelta(depositAmount);
43269
+ }
43270
+ async computeVesuWithdrawDebtDelta(withdrawAmount) {
43271
+ return this.getAdapterById(
43272
+ "vesu_usdc_strk"
43273
+ ).getExpectedWithdrawDebtDelta(withdrawAmount);
43274
+ }
43275
+ async getPendingHyperAssets() {
43276
+ const xstrkToken = Global.getDefaultTokens().find(
43277
+ (t) => t.symbol === "xSTRK"
43278
+ );
43279
+ const hyperXstrkRedeemNFT = ContractAddr.from(
43280
+ "0x51e40b839dc0c2feca923f863072673b94abfa2483345be3b30b457a90d095"
43281
+ );
43282
+ return this.getAdapterById(
43283
+ "hyper_xstrk"
43284
+ ).getPendingAssetsFromOwnerNFTMethod(
43285
+ hyperXstrkRedeemNFT,
43286
+ this.metadata.additionalInfo.vaultAllocator,
43287
+ xstrkToken.decimals
43288
+ );
43289
+ }
43290
+ // TODO: rn we are just making these functions in the strategy itself but
43291
+ // later on we will move them to the SVKStrategy for generalization
43292
+ async getUserTVL(user, blockIdentifier = "latest") {
43293
+ const shares = await this.contract.call("balanceOf", [user.address], {
43294
+ blockIdentifier
43295
+ });
43296
+ const assets = await this.contract.call(
43297
+ "convert_to_assets",
43298
+ [uint25623.bnToUint256(shares)],
43299
+ { blockIdentifier }
43300
+ );
43301
+ const amount = Web3Number.fromWei(
43302
+ assets.toString(),
43303
+ this.metadata.depositTokens[0].decimals
43304
+ );
43305
+ const blockNumber = typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint" ? Number(blockIdentifier) : void 0;
43306
+ const price = await this.pricer.getPrice(
43307
+ this.metadata.depositTokens[0].symbol,
43308
+ blockNumber
43309
+ );
43310
+ const usdValue = Number(amount.toFixed(6)) * price.price;
43311
+ return {
43312
+ tokenInfo: this.asset(),
43313
+ amount,
43314
+ usdValue
43315
+ };
43316
+ }
43317
+ async getTVL() {
43318
+ const assets = await this.contract.total_assets();
43319
+ const amount = Web3Number.fromWei(
43320
+ assets.toString(),
43321
+ this.metadata.depositTokens[0].decimals
43322
+ );
43323
+ const price = await this.pricer.getPrice(
43324
+ this.metadata.depositTokens[0].symbol
43325
+ );
43326
+ const usdValue = Number(amount.toFixed(6)) * price.price;
43327
+ return {
43328
+ tokenInfo: this.asset(),
43329
+ amount,
43330
+ usdValue
43331
+ };
43332
+ }
43333
+ async getAUM() {
43334
+ const underlying = this.asset();
43335
+ const usdcPrice = await this.pricer.getPrice(underlying.symbol);
43336
+ const allPositions = [];
43337
+ for (const adapter of this.metadata.additionalInfo.adapters) {
43338
+ const positions = await adapter.adapter.getPositions();
43339
+ allPositions.push(...positions);
43340
+ }
43341
+ let netAUM = new Web3Number(0, underlying.decimals);
43342
+ for (const position of allPositions) {
43343
+ if (position.tokenInfo.address.eq(underlying.address)) {
43344
+ netAUM = netAUM.plus(position.amount);
43345
+ } else {
43346
+ const valueInUSDC = position.usdValue;
43347
+ netAUM = netAUM.plus(valueInUSDC);
43348
+ }
43349
+ }
43350
+ const unusedBalance = await this.getUnusedBalance();
43351
+ logger.verbose(
43352
+ `${this.getTag()} unused balance: ${unusedBalance.amount.toNumber()}`
43353
+ );
43354
+ netAUM = netAUM.plus(unusedBalance.amount);
43355
+ const prevAum = await this.getPrevAUM();
43356
+ logger.verbose(`${this.getTag()} AUM: ${netAUM}`);
43357
+ const realAUM = {
43358
+ tokenInfo: underlying,
43359
+ amount: netAUM,
43360
+ usdValue: netAUM.toNumber() * usdcPrice.price,
43361
+ apy: { apy: 0, type: "base" /* BASE */ },
43362
+ remarks: "finalised" /* FINALISED */,
43363
+ protocol: Protocols.NONE
43364
+ };
43365
+ const estimatedAUMDelta = {
43366
+ tokenInfo: underlying,
43367
+ amount: Web3Number.fromWei("0", underlying.decimals),
43368
+ usdValue: 0,
43369
+ apy: { apy: 0, type: "base" /* BASE */ },
43370
+ remarks: "defispring" /* DEFISPRING */,
43371
+ protocol: Protocols.NONE
43372
+ };
43373
+ return {
43374
+ net: {
43375
+ tokenInfo: underlying,
43376
+ amount: netAUM,
43377
+ usdValue: netAUM.toNumber() * usdcPrice.price
43378
+ },
43379
+ prevAum,
43380
+ splits: [realAUM, estimatedAUMDelta]
43381
+ };
42169
43382
  }
42170
- };
42171
- var HYPER_LST_REDEMPTION_INFO = {
42172
- instantWithdrawalVault: "No" /* NO */,
42173
- redemptionsInfo: [
42174
- {
42175
- title: "Typical Duration",
42176
- description: "1-2 hours"
43383
+ // TODO: can refactor later but seems redundant since not being used ANYWHERE
43384
+ // Most of the fund management done through adapters only
43385
+ async getFundManagementCall(params) {
43386
+ logger.verbose(
43387
+ `${this.getTag()}::getFundManagementCall params: ${JSON.stringify(params)}`
43388
+ );
43389
+ const allAdapters = this.metadata.additionalInfo.adapters.map(
43390
+ (a) => a.adapter
43391
+ );
43392
+ if (!params.isDeposit) {
43393
+ const unusedBalance = await this.getUnusedBalance();
43394
+ logger.verbose(
43395
+ `${this.getTag()}::getFundManagementCall unusedBalance: ${unusedBalance.amount}, required: ${params.leg1DepositAmount}`
43396
+ );
43397
+ if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
43398
+ return null;
43399
+ }
43400
+ const adapters2 = await AdapterOptimizer.getAdapterToUse(
43401
+ allAdapters,
43402
+ false,
43403
+ params.leg1DepositAmount
43404
+ );
43405
+ if (adapters2.length > 0) {
43406
+ const proofsInfo = adapters2.map(
43407
+ (adapter) => adapter.getProofs(false, this.getMerkleTree())
43408
+ );
43409
+ const calls = [];
43410
+ for (const info of proofsInfo) {
43411
+ const manageCalls = await info.callConstructor({
43412
+ amount: params.leg1DepositAmount
43413
+ });
43414
+ const call = this.getManageCall(
43415
+ this.getProofGroupsForManageCalls(manageCalls),
43416
+ manageCalls
43417
+ );
43418
+ calls.push(call);
43419
+ }
43420
+ return calls;
43421
+ }
43422
+ throw new Error(
43423
+ `${this.getTag()}::getFundManagementCall: no adapters for withdraw: ${unusedBalance.amount}`
43424
+ );
42177
43425
  }
42178
- ],
42179
- alerts: [
42180
- {
42181
- type: "info",
42182
- text: "In cases of low liquidity, high slippages, the redemptions can take longer time. Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
42183
- tab: "withdraw"
43426
+ const adapters = await AdapterOptimizer.getAdapterToUse(
43427
+ allAdapters,
43428
+ true,
43429
+ params.leg1DepositAmount
43430
+ );
43431
+ if (adapters.length > 0) {
43432
+ const proofsInfo = adapters.map(
43433
+ (adapter) => adapter.getProofs(true, this.getMerkleTree())
43434
+ );
43435
+ const calls = [];
43436
+ for (const info of proofsInfo) {
43437
+ const manageCalls = await info.callConstructor({
43438
+ amount: params.leg1DepositAmount
43439
+ });
43440
+ const call = this.getManageCall(
43441
+ this.getProofGroupsForManageCalls(manageCalls),
43442
+ manageCalls
43443
+ );
43444
+ calls.push(call);
43445
+ }
43446
+ return calls;
42184
43447
  }
42185
- ]
43448
+ throw new Error(
43449
+ `${this.getTag()}::getFundManagementCall: no adapters for deposit: ${params.leg1DepositAmount}`
43450
+ );
43451
+ }
42186
43452
  };
42187
- function getStrategySettings(lstSymbol, underlyingSymbol, settings, isPreview = false, isLST) {
43453
+ function getUSDCBoostedSettings(vaultSettings) {
43454
+ vaultSettings.leafAdapters = [];
43455
+ const xSTRKToken = Global.getDefaultTokens().find(
43456
+ (t) => t.symbol === "xSTRK"
43457
+ );
43458
+ const USDCToken = Global.getDefaultTokens().find((t) => t.symbol === "USDC");
43459
+ const STRKToken = Global.getDefaultTokens().find((t) => t.symbol === "STRK");
43460
+ const baseAdapterConfig = {
43461
+ baseToken: USDCToken,
43462
+ supportedPositions: [{ asset: USDCToken, isDebt: false }],
43463
+ networkConfig: getMainnetConfig(),
43464
+ pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
43465
+ vaultAllocator: vaultSettings.vaultAllocator,
43466
+ vaultAddress: vaultSettings.vaultAddress
43467
+ };
43468
+ const vesuModifyPositionAdapter = new VesuModifyPositionAdapter({
43469
+ poolId: vaultSettings.vesuPoolId,
43470
+ collateral: vaultSettings.collateralToken,
43471
+ debt: vaultSettings.debtToken,
43472
+ targetLtv: vaultSettings.targetLTV,
43473
+ maxLtv: vaultSettings.maxLTV,
43474
+ ...baseAdapterConfig,
43475
+ supportedPositions: [
43476
+ { asset: USDCToken, isDebt: false },
43477
+ { asset: STRKToken, isDebt: true }
43478
+ ]
43479
+ });
43480
+ const avnuAdapter = new AvnuAdapter({
43481
+ baseUrl: AVNU_QUOTE_URL,
43482
+ avnuContract: AVNU_EXCHANGE,
43483
+ slippage: 0.01,
43484
+ minimumExtendedPriceDifferenceForSwapOpen: 0,
43485
+ maximumExtendedPriceDifferenceForSwapClosing: 0,
43486
+ ...baseAdapterConfig,
43487
+ baseToken: STRKToken,
43488
+ supportedPositions: [
43489
+ { asset: STRKToken, isDebt: false },
43490
+ { asset: xSTRKToken, isDebt: false }
43491
+ ]
43492
+ });
43493
+ const svkTrovesAdapter = new SvkTrovesAdapter({
43494
+ ...baseAdapterConfig,
43495
+ baseToken: xSTRKToken,
43496
+ supportedPositions: [{ asset: xSTRKToken, isDebt: false }],
43497
+ strategyVault: vaultSettings.hyperxSTRKVaultAddress,
43498
+ trovesStrategyId: "hyper_xstrk"
43499
+ });
43500
+ const usdcTransferAdapter = new TokenTransferAdapter({
43501
+ ...baseAdapterConfig,
43502
+ fromAddress: vaultSettings.vaultAllocator,
43503
+ toAddress: vaultSettings.vaultAddress
43504
+ });
43505
+ const commonAdapter = new CommonAdapter({
43506
+ id: "flash_loan_init" /* FLASH_LOAN */,
43507
+ vaultAddress: vaultSettings.vaultAddress,
43508
+ vaultAllocator: vaultSettings.vaultAllocator,
43509
+ manager: vaultSettings.manager,
43510
+ asset: USDCToken.address
43511
+ });
43512
+ vaultSettings.adapters.push(
43513
+ // TODO: generalize the ids
43514
+ { id: "vesu_usdc_strk", adapter: vesuModifyPositionAdapter },
43515
+ // Used to track swapped funds in vaultAllocator
43516
+ { id: "avnu_strk_xstrk", adapter: avnuAdapter },
43517
+ { id: "hyper_xstrk", adapter: svkTrovesAdapter },
43518
+ { id: "usdc_transfer", adapter: usdcTransferAdapter }
43519
+ );
43520
+ vaultSettings.leafAdapters.push(
43521
+ () => vesuModifyPositionAdapter.getDepositLeaf()
43522
+ );
43523
+ vaultSettings.leafAdapters.push(
43524
+ () => vesuModifyPositionAdapter.getWithdrawLeaf()
43525
+ );
43526
+ vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
43527
+ vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
43528
+ vaultSettings.leafAdapters.push(() => svkTrovesAdapter.getDepositLeaf());
43529
+ vaultSettings.leafAdapters.push(() => svkTrovesAdapter.getWithdrawLeaf());
43530
+ vaultSettings.leafAdapters.push(
43531
+ commonAdapter.getApproveAdapter(
43532
+ USDCToken.address,
43533
+ vaultSettings.vaultAddress,
43534
+ "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */
43535
+ ).bind(commonAdapter)
43536
+ );
43537
+ vaultSettings.leafAdapters.push(
43538
+ commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter)
43539
+ );
43540
+ return vaultSettings;
43541
+ }
43542
+ var usdcBoostedSettings = {
43543
+ vaultAddress: ContractAddr.from(
43544
+ "0xcdb0e3b2e076a2cdc4ee958b726b47c066239ef91c5ac80c94cf814147b84"
43545
+ ),
43546
+ manager: ContractAddr.from(
43547
+ "0x72eea9bac9fa8cfffda637d3b990851446860c6fd8987d6cb50e659b01ee50f"
43548
+ ),
43549
+ vaultAllocator: ContractAddr.from(
43550
+ "0x6d3101cff7f821412a99ebe23bb31a1950f93276285102eb4313e3601f5f927"
43551
+ ),
43552
+ redeemRequestNFT: ContractAddr.from(
43553
+ "0x47dcc6889ca8db4e9eea8f55421e10f8ce7e356ccb45260a1c49a76f733c309"
43554
+ ),
43555
+ // TODO: not applicable in our case -> remove later ( make it optional if needed)
43556
+ aumOracle: ContractAddr.from("0x0"),
43557
+ leafAdapters: [],
43558
+ adapters: [],
43559
+ // Calc using the maxLTV / targetLTV (0.5)
43560
+ targetHealthFactor: 1.32,
43561
+ // Calc using the maxLTV / maxAcceptableLTV (0.55)
43562
+ minHealthFactor: 1.2,
43563
+ vesuPoolId: VesuPools.Prime,
43564
+ collateralToken: Global.getDefaultTokens().find((t) => t.symbol === "USDC"),
43565
+ debtToken: Global.getDefaultTokens().find((t) => t.symbol === "STRK"),
43566
+ maxLTV: 0.66,
43567
+ targetLTV: 0.5,
43568
+ hyperxSTRKVaultAddress: ContractAddr.from(
43569
+ "0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960"
43570
+ )
43571
+ };
43572
+ function getStrategySettings2(settings) {
43573
+ const USDCToken = Global.getDefaultTokens().find((t) => t.symbol === "USDC");
43574
+ const STRKToken = Global.getDefaultTokens().find((t) => t.symbol === "STRK");
42188
43575
  return {
42189
- id: `hyper_${lstSymbol.toLowerCase()}`,
42190
- name: `Hyper ${lstSymbol}`,
42191
- description: getDescription2(lstSymbol, underlyingSymbol),
43576
+ id: "usdc_boosted",
43577
+ name: "USDC Boosted",
43578
+ description: "Deposits USDC as collateral on Vesu, borrows STRK, swaps to xSTRK, and deposits into Hyper-xSTRK for boosted yield",
42192
43579
  address: settings.vaultAddress,
42193
- launchBlock: 0,
42194
- type: "Other",
43580
+ launchBlock: 8742931,
43581
+ type: "ERC4626",
42195
43582
  vaultType: {
42196
- type: "Looping" /* LOOPING */,
42197
- description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`
43583
+ // TODO: can change as per need
43584
+ type: "Meta Vault" /* META_VAULT */,
43585
+ description: "Deposits USDC as collateral on Vesu, borrows STRK, swaps to xSTRK, and deposits into Hyper-xSTRK for boosted yield"
42198
43586
  },
42199
- depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === lstSymbol)],
42200
- additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, settings, lstSymbol === "xSTRK" ? VesuPools.Re7xSTRK : VesuPools.Re7xBTC),
43587
+ depositTokens: [USDCToken],
43588
+ additionalInfo: getUSDCBoostedSettings(settings),
43589
+ // TODO: config lateron
42201
43590
  risk: {
42202
- riskFactor: _riskFactor4,
42203
- netRisk: _riskFactor4.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor4.reduce((acc, curr) => acc + curr.weight, 0),
42204
- notARisks: getNoRiskTags(_riskFactor4)
43591
+ riskFactor: [],
43592
+ netRisk: 0,
43593
+ notARisks: []
42205
43594
  },
42206
- auditUrl: AUDIT_URL4,
42207
- protocols: [Protocols.ENDUR, Protocols.VESU],
43595
+ protocols: [Protocols.VESU, Protocols.TROVES],
42208
43596
  curator: {
42209
43597
  name: "Unwrap Labs",
42210
43598
  logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
42211
43599
  },
42212
- settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
43600
+ settings: {
43601
+ maxTVL: Web3Number.fromWei(0, USDCToken.decimals),
43602
+ isPaused: false,
43603
+ isAudited: false,
43604
+ isInstantWithdrawal: false,
43605
+ hideHarvestInfo: true,
43606
+ quoteToken: USDCToken,
43607
+ alerts: [
43608
+ {
43609
+ tab: "withdraw",
43610
+ text: "On withdrawal, you will receive an NFT representing your withdrawal request. The funds will be automatically sent to your wallet (NFT owner) in 1-2 hours. You can monitor the status in transactions tab.",
43611
+ type: "info"
43612
+ }
43613
+ ]
43614
+ },
42213
43615
  contractDetails: getContractDetails(settings),
42214
- faqs: getFAQs2(lstSymbol, underlyingSymbol, isLST),
42215
- investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
42216
- isPreview,
42217
- apyMethodology: "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.",
42218
- realizedAPYMethodology: "The realizedAPY is based on past 14 days performance by the vault",
42219
- tags: lstSymbol.includes("BTC") ? ["BTC" /* BTC */, "Maxx" /* LEVERED */] : ["Maxx" /* LEVERED */],
42220
- security: HYPER_LST_SECURITY,
42221
- redemptionInfo: HYPER_LST_REDEMPTION_INFO,
42222
- usualTimeToEarnings: "2 weeks",
42223
- usualTimeToEarningsDescription: "Strategy returns depend on LST price on DEXes. Even though the true price of LST on Endur increases continuously, the DEX price may lag sometimes, and historically is seen to rebase at least once every 2 hours. This is when you realise your earnings.",
42224
- points: lstSymbol === "xSTRK" ? [{
42225
- multiplier: 4,
42226
- logo: "https://endur.fi/favicon.ico",
42227
- toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi."
42228
- }] : void 0
43616
+ // TODO: config later
43617
+ faqs: [],
43618
+ investmentSteps: [
43619
+ "Deposit USDC into the vault",
43620
+ "USDC is supplied as collateral on Vesu, STRK is borrowed",
43621
+ "Borrowed STRK is swapped to xSTRK via Avnu",
43622
+ "xSTRK is deposited into the Hyper-xSTRK vault for additional yield",
43623
+ "On withdrawal, the pipeline reverses to return USDC"
43624
+ ],
43625
+ // TODO: config later
43626
+ tags: ["Meta Vaults" /* META_VAULT */],
43627
+ security: {
43628
+ auditStatus: "Audited" /* AUDITED */,
43629
+ sourceCode: {
43630
+ type: "Closed Source" /* CLOSED_SOURCE */,
43631
+ contractLink: "https://github.com/trovesfi/troves-contracts"
43632
+ },
43633
+ accessControl: {
43634
+ type: "Standard Account" /* STANDARD_ACCOUNT */,
43635
+ addresses: [ContractAddr.from("0x0")],
43636
+ timeLock: "2 Days"
43637
+ }
43638
+ },
43639
+ redemptionInfo: {
43640
+ instantWithdrawalVault: "No" /* NO */,
43641
+ redemptionsInfo: [
43642
+ {
43643
+ title: "Typical Duration",
43644
+ description: "1-2 hours"
43645
+ }
43646
+ ],
43647
+ alerts: [
43648
+ {
43649
+ type: "info",
43650
+ text: "Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
43651
+ tab: "withdraw"
43652
+ }
43653
+ ]
43654
+ },
43655
+ usualTimeToEarnings: null,
43656
+ usualTimeToEarningsDescription: null
42229
43657
  };
42230
43658
  }
42231
- var HyperLSTStrategies = [
42232
- getStrategySettings("xSTRK", "STRK", hyperxSTRK, false, true),
42233
- getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false, false),
42234
- getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false, false),
42235
- getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false, false),
42236
- getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false, false),
42237
- getStrategySettings("mRe7BTC", "mRe7BTC", hypermRe7BTC, false, false),
42238
- getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
42239
- ];
43659
+ var USDCBoostedStrategies = [getStrategySettings2(usdcBoostedSettings)];
42240
43660
 
42241
43661
  // src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts
42242
43662
  function ceilBtc(v, precision) {
@@ -43635,6 +45055,142 @@ function createSolveBudgetFromRawState(params) {
43635
45055
  }
43636
45056
  return budget;
43637
45057
  }
45058
+ function assertRouteSanityAndAdjust(route, availableAmount) {
45059
+ if (!route.amount) {
45060
+ throw new Error(`Invalid route given to assertRouteSanityAndAdjust: ${JSON.stringify(route)}`);
45061
+ }
45062
+ const routeAmount = route.amount.toNumber();
45063
+ if (routeAmount <= availableAmount) {
45064
+ return route;
45065
+ }
45066
+ if (routeAmount - availableAmount <= CASE_THRESHOLD_USD) {
45067
+ return { ...route, amount: new Web3Number(availableAmount, route.amount.decimals) };
45068
+ }
45069
+ throw new Error(`Route amount ${routeAmount} exceeds available amount ${availableAmount}, Route name: ${route.type}`);
45070
+ }
45071
+ function assertVesuMultiplyRouteSanityAndAdjust(route, availableAmount, state, isIncrease) {
45072
+ const btcPrice = state.vesuPoolState.collateralPrice;
45073
+ const totalCollateralAmount = isIncrease ? route.marginAmount.plus(route.swappedCollateralAmount).plus(state.vesuPoolState.collateralAmount) : state.vesuPoolState.collateralAmount.minus(route.marginAmount.plus(route.swappedCollateralAmount));
45074
+ const totalDebtAmount = isIncrease ? route.debtAmount.plus(state.vesuPoolState.debtAmount) : state.vesuPoolState.debtAmount.minus(route.debtAmount);
45075
+ const newHF = HealthFactorMath.getHealthFactor(
45076
+ totalCollateralAmount,
45077
+ btcPrice,
45078
+ VesuConfig.maxLtv,
45079
+ totalDebtAmount,
45080
+ state.vesuPoolState.debtPrice
45081
+ );
45082
+ const idealHF = VesuConfig.maxLtv / VesuConfig.targetLtv - 0.05;
45083
+ assert(newHF >= idealHF, `SolveBudget::applyRoutesAndVerifyLtvState newHF=${newHF} < idealHF=${idealHF}`);
45084
+ }
45085
+ function applyRoutesAndVerifyLtvState(state, routes) {
45086
+ const btcPrice = state.vesuPoolState.collateralPrice;
45087
+ const adjustedRouters = [...routes];
45088
+ let index = 0;
45089
+ for (const r of routes) {
45090
+ switch (r.type) {
45091
+ case "WALLET_TO_VA" /* WALLET_TO_VA */: {
45092
+ const adjustedRoute = assertRouteSanityAndAdjust(r, state.walletUsd);
45093
+ const amt = adjustedRoute.amount.toNumber();
45094
+ state.spendWallet(amt);
45095
+ state.addToVA(amt);
45096
+ break;
45097
+ }
45098
+ case "VESU_REPAY" /* VESU_REPAY */: {
45099
+ const adjustedRoute = assertRouteSanityAndAdjust(r, state.vaRawUsd);
45100
+ const amt = Math.abs(adjustedRoute.amount.toNumber());
45101
+ state.repayVesuBorrowCapacity(amt);
45102
+ state.spendVA(amt);
45103
+ break;
45104
+ }
45105
+ case "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */: {
45106
+ const adjustedRoute = assertRouteSanityAndAdjust(r, state.extAvailWithdraw);
45107
+ const amt = adjustedRoute.amount.toNumber();
45108
+ state.addToWallet(amt);
45109
+ state.spendExtAvailTrade(amt);
45110
+ break;
45111
+ }
45112
+ case "REALISE_PNL" /* REALISE_PNL */: {
45113
+ const amt = r.amount.toNumber();
45114
+ state.spendExtAvailUpnl(amt);
45115
+ state.addToExtAvailTrade(amt);
45116
+ break;
45117
+ }
45118
+ case "VA_TO_EXTENDED" /* VA_TO_EXTENDED */: {
45119
+ const adjustedRoute = assertRouteSanityAndAdjust(r, state.vaRawUsd);
45120
+ const amt = adjustedRoute.amount.toNumber();
45121
+ state.spendVA(amt);
45122
+ state.addToExtAvailTrade(amt);
45123
+ break;
45124
+ }
45125
+ case "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */: {
45126
+ const adjustedRoute = assertRouteSanityAndAdjust(r, state.walletUsd);
45127
+ const amt = adjustedRoute.amount.toNumber();
45128
+ state.spendWallet(amt);
45129
+ state.addToExtAvailTrade(amt);
45130
+ break;
45131
+ }
45132
+ case "VESU_BORROW" /* VESU_BORROW */: {
45133
+ const borrowedAmount = r.amount.toNumber();
45134
+ const currentCollateralAmount = state.vesuPoolState.collateralAmount.toNumber();
45135
+ const currentDebtAmount = state.vesuPoolState.debtAmount.toNumber();
45136
+ const maxDebtAmount = HealthFactorMath.getMaxDebtAmount(
45137
+ new Web3Number(currentCollateralAmount, state.vesuPoolState.collateralToken.decimals),
45138
+ state.vesuPoolState.collateralPrice,
45139
+ VesuConfig.maxLtv,
45140
+ VesuConfig.maxLtv / VesuConfig.targetLtv - 0.05,
45141
+ // e.g. if ideal HF is 1.4, upto 1.35 is ok.
45142
+ state.vesuPoolState.debtPrice,
45143
+ state.vesuPoolState.debtToken
45144
+ );
45145
+ const availableDebtAmount = maxDebtAmount.minus(new Web3Number(currentDebtAmount, state.vesuPoolState.debtToken.decimals));
45146
+ if (!availableDebtAmount.plus(CASE_THRESHOLD_USD).greaterThan(borrowedAmount)) {
45147
+ throw new Error(`SolveBudget::applyRoutesAndVerifyLtvState availableDebtAmount=${availableDebtAmount.toNumber()} < borrowedAmount=${borrowedAmount}`);
45148
+ }
45149
+ state.spendVesuBorrowCapacity(borrowedAmount);
45150
+ state.addToVA(borrowedAmount);
45151
+ break;
45152
+ }
45153
+ case "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */: {
45154
+ const mr = r;
45155
+ assertVesuMultiplyRouteSanityAndAdjust(mr, state.vaRawUsd, state, true);
45156
+ state.applyVesuDelta(
45157
+ mr.poolId,
45158
+ mr.collateralToken,
45159
+ mr.debtToken,
45160
+ mr.marginAmount.plus(mr.swappedCollateralAmount),
45161
+ mr.debtAmount
45162
+ );
45163
+ state.spendVA(mr.marginAmount.toNumber() * btcPrice);
45164
+ break;
45165
+ }
45166
+ case "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */: {
45167
+ const mr = r;
45168
+ assertVesuMultiplyRouteSanityAndAdjust(mr, state.vaRawUsd, state, false);
45169
+ state.applyVesuDelta(
45170
+ mr.poolId,
45171
+ mr.collateralToken,
45172
+ mr.debtToken,
45173
+ new Web3Number(mr.marginAmount.negated().minus(mr.swappedCollateralAmount).toFixed(8), mr.marginAmount.decimals),
45174
+ mr.debtAmount
45175
+ );
45176
+ const marginBtc = mr.marginAmount.toNumber();
45177
+ if (marginBtc > 10 ** -COLLATERAL_PRECISION) {
45178
+ state.addToVA(marginBtc * btcPrice);
45179
+ }
45180
+ break;
45181
+ }
45182
+ case "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */:
45183
+ case "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */: {
45184
+ const er = r;
45185
+ state.applyExtendedExposureDelta(er.instrument, er.amount, btcPrice);
45186
+ break;
45187
+ }
45188
+ case "RETURN_TO_WAIT" /* RETURN_TO_WAIT */:
45189
+ break;
45190
+ }
45191
+ index++;
45192
+ }
45193
+ }
43638
45194
  var ExtendedSVKVesuStateManager = class {
43639
45195
  constructor(config) {
43640
45196
  this._tag = "ExtendedSVKVesuStateManager";
@@ -43653,13 +45209,19 @@ var ExtendedSVKVesuStateManager = class {
43653
45209
  * Pass 0 (default) for normal investment / rebalancing cycles.
43654
45210
  */
43655
45211
  async solve(withdrawAmount = new Web3Number(0, USDC_TOKEN_DECIMALS)) {
43656
- await this._refresh();
45212
+ const gaurdrailBudget = await this._refresh();
43657
45213
  if (Math.abs(this._budget.extPendingDeposit) > 0) {
43658
45214
  logger.warn(`${this._tag}::solve extPendingDeposit=${this._budget.extPendingDeposit}`);
43659
45215
  return null;
43660
45216
  }
43661
45217
  this._validateRefreshedState();
43662
45218
  const cases = this._classifyCases(withdrawAmount);
45219
+ for (const c of cases) {
45220
+ applyRoutesAndVerifyLtvState(gaurdrailBudget, c.routes);
45221
+ }
45222
+ const extendedPositionSize = gaurdrailBudget.extendedPositionsView[0].size.toNumber();
45223
+ const vesuPositionSize = gaurdrailBudget.vesuPoolState.collateralAmount.toNumber();
45224
+ assert(Math.abs(extendedPositionSize - vesuPositionSize) <= 1e-5, "extended positions size mismatch");
43663
45225
  const result = {
43664
45226
  cases,
43665
45227
  // ignore these fields for now. only cases are relevant.
@@ -43707,7 +45269,7 @@ var ExtendedSVKVesuStateManager = class {
43707
45269
  vaultUsdcBalance,
43708
45270
  walletBalance
43709
45271
  );
43710
- this._budget = createSolveBudgetFromRawState({
45272
+ const data = {
43711
45273
  assetToken: this._config.assetToken,
43712
45274
  usdcToken: this._config.usdcToken,
43713
45275
  unusedBalance,
@@ -43724,7 +45286,9 @@ var ExtendedSVKVesuStateManager = class {
43724
45286
  pendingDeposit: extendedBalance?.pendingDeposit || new Web3Number(0, USDC_TOKEN_DECIMALS)
43725
45287
  },
43726
45288
  vesuPoolStates
43727
- });
45289
+ };
45290
+ this._budget = createSolveBudgetFromRawState(data);
45291
+ const gaurdrailBudget = createSolveBudgetFromRawState({ ...data });
43728
45292
  this._budget.logStateSummary();
43729
45293
  const totalUnusedUsd = unusedBalance.reduce(
43730
45294
  (acc, b) => acc + b.usdValue,
@@ -43733,6 +45297,7 @@ var ExtendedSVKVesuStateManager = class {
43733
45297
  logger.info(
43734
45298
  `${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()}`
43735
45299
  );
45300
+ return gaurdrailBudget;
43736
45301
  }
43737
45302
  // todo add communication check with python server of extended. if not working, throw error in solve function.
43738
45303
  /** True when strategy asset and USDC share one token — VA idle balance is tracked as USDC, not as asset. */
@@ -45476,7 +47041,7 @@ var ExtendedSVKVesuStateManager = class {
45476
47041
  };
45477
47042
 
45478
47043
  // src/strategies/vesu-extended-strategy/services/executionService.ts
45479
- import { uint256 as uint25623 } from "starknet";
47044
+ import { uint256 as uint25624 } from "starknet";
45480
47045
 
45481
47046
  // src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
45482
47047
  var CycleType = /* @__PURE__ */ ((CycleType2) => {
@@ -46408,7 +47973,7 @@ var _ExecutionService = class _ExecutionService {
46408
47973
  const extendedContract = extendedAdapter.config.extendedContract;
46409
47974
  const vaultId = extendedAdapter.config.vaultIdExtended;
46410
47975
  const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
46411
- const uint256Amount = uint25623.bnToUint256(amount.toWei());
47976
+ const uint256Amount = uint25624.bnToUint256(amount.toWei());
46412
47977
  const approveCall = {
46413
47978
  contractAddress: usdcToken.address.address,
46414
47979
  entrypoint: "approve",
@@ -48364,7 +49929,7 @@ var PricerRedis = class extends Pricer {
48364
49929
  };
48365
49930
 
48366
49931
  // src/node/deployer.ts
48367
- import assert2 from "assert";
49932
+ import assert3 from "assert";
48368
49933
  import { Deployer as SnDeployer, TransactionExecutionStatus, constants as constants3, extractContractHashes, json, num as num14 } from "starknet";
48369
49934
  import { readFileSync as readFileSync2, existsSync, writeFileSync as writeFileSync2 } from "fs";
48370
49935
 
@@ -48633,8 +50198,8 @@ async function prepareMultiDeployContracts(contracts, config, acc) {
48633
50198
  classHash,
48634
50199
  constructorCalldata: constructorData
48635
50200
  }, acc.address);
48636
- assert2(calls.length == 1, `Expected exactly one call, got ${calls.length}`);
48637
- assert2(addresses.length == 1, `Expected exactly one address, got ${addresses.length}`);
50201
+ assert3(calls.length == 1, `Expected exactly one call, got ${calls.length}`);
50202
+ assert3(addresses.length == 1, `Expected exactly one address, got ${addresses.length}`);
48638
50203
  result.push({
48639
50204
  contract_name,
48640
50205
  package_name,
@@ -48647,7 +50212,7 @@ async function prepareMultiDeployContracts(contracts, config, acc) {
48647
50212
  }
48648
50213
  async function executeDeployCalls(contractsInfo, acc, provider2) {
48649
50214
  for (let contractInfo of contractsInfo) {
48650
- assert2(num14.toHexString(contractInfo.call.contractAddress) == num14.toHexString(constants3.UDC.ADDRESS), "Must be pointed at UDC address");
50215
+ assert3(num14.toHexString(contractInfo.call.contractAddress) == num14.toHexString(constants3.UDC.ADDRESS), "Must be pointed at UDC address");
48651
50216
  }
48652
50217
  const allCalls = contractsInfo.map((info) => info.call);
48653
50218
  await executeTransactions(allCalls, acc, provider2, `Deploying contracts: ${contractsInfo.map((info) => info.contract_name).join(", ")}`);
@@ -48791,6 +50356,7 @@ export {
48791
50356
  SIMPLE_SANITIZER,
48792
50357
  SIMPLE_SANITIZER_V2,
48793
50358
  SIMPLE_SANITIZER_VESU_V1_DELEGATIONS,
50359
+ SVK_SIMPLE_SANITIZER,
48794
50360
  SenseiStrategies,
48795
50361
  SenseiVault,
48796
50362
  SolveBudget,
@@ -48810,6 +50376,8 @@ export {
48810
50376
  TokenTransferAdapter,
48811
50377
  UNIVERSAL_ADAPTERS,
48812
50378
  UNIVERSAL_MANAGE_IDS,
50379
+ USDCBoostedStrategies,
50380
+ USDCBoostedStrategy,
48813
50381
  UniversalLstMultiplierStrategy,
48814
50382
  UniversalStrategies,
48815
50383
  UniversalStrategy,