@1delta/margin-fetcher 5.0.75 → 5.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -48279,6 +48279,109 @@ var scrvusdFetcher = {
48279
48279
  };
48280
48280
  }
48281
48281
  };
48282
+ var SUSDAT = "0xd166337499e176bbc38a1fbd113ab144e5bd2df7";
48283
+ var DEFILLAMA_POOL = "47e72726-3b2b-4fe6-b4a9-a26e1fcd9a50";
48284
+ var YEAR_SECONDS11 = 31536e3;
48285
+ var STRC_UNIT = 1e6;
48286
+ var SUSDAT_KEY = "Saturn sUSDat::SUSDAT";
48287
+ var SUSDAT_BRIDGED_KEY = "Staked Saturn USD::sUSDat";
48288
+ var VAULT_ABI = [
48289
+ {
48290
+ name: "vestingAmount",
48291
+ type: "function",
48292
+ stateMutability: "view",
48293
+ inputs: [],
48294
+ outputs: [{ name: "", type: "uint256" }]
48295
+ },
48296
+ {
48297
+ name: "vestingPeriod",
48298
+ type: "function",
48299
+ stateMutability: "view",
48300
+ inputs: [],
48301
+ outputs: [{ name: "", type: "uint256" }]
48302
+ },
48303
+ {
48304
+ name: "totalAssets",
48305
+ type: "function",
48306
+ stateMutability: "view",
48307
+ inputs: [],
48308
+ outputs: [{ name: "", type: "uint256" }]
48309
+ },
48310
+ {
48311
+ name: "getStrcOracle",
48312
+ type: "function",
48313
+ stateMutability: "view",
48314
+ inputs: [],
48315
+ outputs: [{ name: "", type: "address" }]
48316
+ }
48317
+ ];
48318
+ var STRC_ORACLE_ABI = [
48319
+ {
48320
+ name: "getPrice",
48321
+ type: "function",
48322
+ stateMutability: "view",
48323
+ inputs: [],
48324
+ outputs: [
48325
+ { name: "price", type: "uint256" },
48326
+ { name: "decimals", type: "uint8" }
48327
+ ]
48328
+ }
48329
+ ];
48330
+ var decodeStrcPrice = (cell) => {
48331
+ if (Array.isArray(cell) && cell.length >= 2) {
48332
+ return { price: BigInt(cell[0]), priceDecimals: Number(cell[1]) };
48333
+ }
48334
+ if (cell && typeof cell === "object") {
48335
+ const o = cell;
48336
+ if (o.price !== void 0 && o.decimals !== void 0) {
48337
+ return {
48338
+ price: BigInt(o.price),
48339
+ priceDecimals: Number(o.decimals)
48340
+ };
48341
+ }
48342
+ }
48343
+ throw new Error("sUSDat: unrecognised STRC oracle response shape");
48344
+ };
48345
+ var computeIncomeApr = async () => {
48346
+ const [vestingAmount, vestingPeriod, totalAssets, oracle] = await multicallRetryUniversal({
48347
+ chain: Chain.ETHEREUM_MAINNET,
48348
+ abi: VAULT_ABI,
48349
+ calls: [
48350
+ { address: SUSDAT, name: "vestingAmount", params: [] },
48351
+ { address: SUSDAT, name: "vestingPeriod", params: [] },
48352
+ { address: SUSDAT, name: "totalAssets", params: [] },
48353
+ { address: SUSDAT, name: "getStrcOracle", params: [] }
48354
+ ],
48355
+ allowFailure: false
48356
+ });
48357
+ if (vestingPeriod <= 0n || totalAssets <= 0n) {
48358
+ throw new Error("sUSDat: empty vault or zero vesting period");
48359
+ }
48360
+ const [oracleCell] = await multicallRetryUniversal({
48361
+ chain: Chain.ETHEREUM_MAINNET,
48362
+ abi: STRC_ORACLE_ABI,
48363
+ calls: [{ address: oracle, name: "getPrice", params: [] }],
48364
+ allowFailure: false
48365
+ });
48366
+ const { price: price2, priceDecimals } = decodeStrcPrice(oracleCell);
48367
+ if (price2 <= 0n) throw new Error("sUSDat: STRC oracle returned no price");
48368
+ const strcPriceUsd = Number(price2) / 10 ** Number(priceDecimals);
48369
+ const rewardUsd = Number(vestingAmount) / STRC_UNIT * strcPriceUsd;
48370
+ const cyclesPerYear = YEAR_SECONDS11 / Number(vestingPeriod);
48371
+ const tvlUsd = Number(totalAssets) / 1e6;
48372
+ const apr = rewardUsd * cyclesPerYear / tvlUsd * 100;
48373
+ if (!Number.isFinite(apr) || apr < 0) {
48374
+ throw new Error("sUSDat: implausible income APR");
48375
+ }
48376
+ return apr;
48377
+ };
48378
+ var saturnFetcher = {
48379
+ label: "SATURN_SUSDAT",
48380
+ fetch: async () => {
48381
+ const apr = await computeIncomeApr().catch(() => fetchDefiLlamaApy(DEFILLAMA_POOL)).catch(() => 0);
48382
+ return { [SUSDAT_KEY]: apr, [SUSDAT_BRIDGED_KEY]: apr };
48383
+ }
48384
+ };
48282
48385
  var thBill = "Theo Short Duration US Treasury Fund::THBILL";
48283
48386
  var thBillBare = "thBILL::thBILL";
48284
48387
  var THBILL_DEFILLAMA_POOL = "e17dab50-85b1-45e8-b4a5-b8ae7898c4a3";
@@ -48360,7 +48463,7 @@ var sthusdFetcher = {
48360
48463
  }
48361
48464
  };
48362
48465
  var RAY9 = 10n ** 27n;
48363
- var YEAR_SECONDS11 = 31536e3;
48466
+ var YEAR_SECONDS12 = 31536e3;
48364
48467
  var DSR_ABI = [
48365
48468
  {
48366
48469
  name: "dsr",
@@ -48388,7 +48491,7 @@ var SUSDD_GROUP_KEY = "Savings Usdd::sUSDD";
48388
48491
  var aprFromDsr = (dsr) => {
48389
48492
  if (dsr <= RAY9) return 0;
48390
48493
  const perSecond = Number(dsr - RAY9) / 1e27;
48391
- return perSecond * YEAR_SECONDS11 * 100;
48494
+ return perSecond * YEAR_SECONDS12 * 100;
48392
48495
  };
48393
48496
  var fetchChainDsr = async (chainId, pot) => {
48394
48497
  const [dsr] = await multicallRetryUniversal({
@@ -50565,6 +50668,102 @@ var VESPER_ENTRIES = {
50565
50668
  }
50566
50669
  ]
50567
50670
  };
50671
+ var VENUS_CORE_COMPTROLLER = "0xfd36e2c2a6789db23113685031d7f16329158384";
50672
+ var VENUS_RESILIENT_ORACLE = "0x6592b5de802159f3e74b2486b091d11a8256ab8a";
50673
+ var XVS = "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63";
50674
+ var hubBase = {
50675
+ reader: "venus-hub",
50676
+ brand: "Venus",
50677
+ // Share decimals are 24 — `decimalsOffset(6)` on an 18-decimal underlying.
50678
+ // Getting this wrong is silent: the exchange rate reads 1e-6 of par.
50679
+ decimals: 24,
50680
+ underlyingDecimals: 18,
50681
+ isRebasing: false,
50682
+ isMintable: true,
50683
+ withdrawalMode: "instant-capped",
50684
+ // Asserted, not assumed — every leg is collateral-backed with an on-chain
50685
+ // liquidation threshold, incl. the FRV one whose docs read like unsecured
50686
+ // credit. See the note above for the live ratios and the two qualifications
50687
+ // that live in the descriptions instead.
50688
+ solvency: "overcollateralized"
50689
+ // No `yieldFetcher`: the rate is the groups' TVL-weighted `spotAPYBps()`,
50690
+ // which the reader computes from the same block's `totalAssets()` reads.
50691
+ // There is nothing off-chain to fall back to — the Hub publishes no APY
50692
+ // view by design, `api.venus.io` has no Hub route, and DefiLlama carries
50693
+ // only `venus-core-pool` / `venus-flux` pools.
50694
+ };
50695
+ var EXIT_PROSE = "Exits are same-transaction and free, but capped at the liquid legs: anything sitting in a Fixed-Rate Vault is locked until it matures, typically a 30-day term.";
50696
+ var BACKING_PROSE = "Every leg is overcollateralised, though not all of it is Venus: Flux lends through third-party Fluid, and a Fixed-Rate Vault is one institutional borrower posting custodial or real-world-asset collateral rather than a pool.";
50697
+ var VENUS_HUB_ENTRIES = {
50698
+ [Chain.BNB_SMART_CHAIN_MAINNET]: [
50699
+ {
50700
+ ...hubBase,
50701
+ address: "0x18afdacf30f8671021dec4b78297e39d2fe87226",
50702
+ underlying: "0x55d398326f99059ff775485246999027b3197955",
50703
+ symbol: "vhUSDT",
50704
+ description: `Venus's USDT Liquidity Hub cascades one deposit across Venus Core lending, Fluid and Venus Fixed-Rate Vaults; the share price is the blend. ${EXIT_PROSE} ${BACKING_PROSE}`,
50705
+ venusHub: {
50706
+ yieldGroups: [
50707
+ "0xc9e6ced9589363f8dc5695be2c79ab4ddaecc94b",
50708
+ "0xe3df38e12e37ed80e1b3ccf2bdf84f9e1527ce14",
50709
+ "0x621ef38ce0c4e7060ff0bf3d609e3d46ec144be7"
50710
+ ],
50711
+ core: {
50712
+ yieldGroup: "0xc9e6ced9589363f8dc5695be2c79ab4ddaecc94b",
50713
+ vToken: "0xfd5840cd36d94d7229439859c0112a4185bc0255",
50714
+ comptroller: VENUS_CORE_COMPTROLLER,
50715
+ oracle: VENUS_RESILIENT_ORACLE,
50716
+ rewardToken: XVS
50717
+ }
50718
+ }
50719
+ },
50720
+ {
50721
+ ...hubBase,
50722
+ address: "0x9d2d9592cf8dfbf59107faab703d08494be14617",
50723
+ underlying: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
50724
+ symbol: "vhUSDC",
50725
+ description: `Venus's USDC Liquidity Hub cascades one deposit across Venus Core lending, Fluid and Venus Fixed-Rate Vaults; the share price is the blend. ${EXIT_PROSE} ${BACKING_PROSE}`,
50726
+ venusHub: {
50727
+ yieldGroups: [
50728
+ "0x299d9be7cefff91c68f13f267d525cfc18e965ef",
50729
+ "0xa65bb4b20542268b64cf08871a98d75342afe927",
50730
+ "0x438388847ee16850ab4f5b82dc7954c0d043b716"
50731
+ ],
50732
+ core: {
50733
+ yieldGroup: "0x299d9be7cefff91c68f13f267d525cfc18e965ef",
50734
+ vToken: "0xeca88125a5adbe82614ffc12d0db554e2e2867c8",
50735
+ comptroller: VENUS_CORE_COMPTROLLER,
50736
+ oracle: VENUS_RESILIENT_ORACLE,
50737
+ rewardToken: XVS
50738
+ }
50739
+ }
50740
+ },
50741
+ {
50742
+ ...hubBase,
50743
+ address: "0x0e5aa174d4f31b757a237eb1999de151596788b0",
50744
+ underlying: "0xce24439f2d9c6a2289f741120fe202248b666666",
50745
+ symbol: "vhU",
50746
+ description: `Venus's Liquidity Hub for U (United Stables) cascades one deposit across Venus Core lending, Fluid and Venus Fixed-Rate Vaults; the share price is the blend. ${EXIT_PROSE} ${BACKING_PROSE}`,
50747
+ venusHub: {
50748
+ yieldGroups: [
50749
+ "0x8a680f77a5367fa7cd33a02f51896cb1d55159c3",
50750
+ "0xe31b8851c3fa9b3dd39a04a2ed9493869a410616",
50751
+ "0x30908eddb9e94add7ac9944a0adda66d80b89143"
50752
+ ],
50753
+ core: {
50754
+ yieldGroup: "0x8a680f77a5367fa7cd33a02f51896cb1d55159c3",
50755
+ vToken: "0x3d5e269787d562b74acc55f18bd26c5d09fa245e",
50756
+ comptroller: VENUS_CORE_COMPTROLLER,
50757
+ oracle: VENUS_RESILIENT_ORACLE,
50758
+ rewardToken: XVS
50759
+ }
50760
+ }
50761
+ }
50762
+ ]
50763
+ };
50764
+ ({
50765
+ [Chain.BNB_SMART_CHAIN_MAINNET]: "0x6d93fd479f2d37445cfbe132412e316a0364acc2"
50766
+ });
50568
50767
 
50569
50768
  // src/vaults/savings/registry.ts
50570
50769
  var stUsdGroup = {
@@ -51255,6 +51454,68 @@ var SINGLE_CHAIN_ENTRIES = {
51255
51454
  yieldFetcher: apyxFetcher,
51256
51455
  yieldKey: APYUSD_KEY
51257
51456
  },
51457
+ // ---- Saturn (saturn.credit) — USDat / sUSDat ----------------------
51458
+ //
51459
+ // `USDat` is an M^0 extension token (a wrapped `$M` claim on tokenized
51460
+ // Treasuries) and `sUSDat` is the vault that stakes it into **Strategy's
51461
+ // STRC**, the variable-rate perpetual preferred stock, passing the
51462
+ // dividend through. Ethereum only: the same addresses on BNB (56) and
51463
+ // Monad (143) are bare LayerZero OFT mirrors whose entire 4626 surface
51464
+ // reverts, so staking round-trips to mainnet (the Cap / Apyx / Brix
51465
+ // precedent) — Monad nevertheless holds $31.1M of USDat.
51466
+ //
51467
+ // Registered `volatile`, and the reason is the whole assessment.
51468
+ // `totalAssets = usdatBalance + (strcBalance − unvested) × STRC price`,
51469
+ // and 96.5 % of NAV is STRC held outright — 723,435.68 STRC against just
51470
+ // $2.55M of actual USDat, with the implied $97.8893 matching Chainlink
51471
+ // STRC/USD to 0.01 %. So the solvency invariant is genuinely on-chain and
51472
+ // checkable (better than Spark V2 / Maple / Native, none of which can be),
51473
+ // and the share price nonetheless moves with a preferred stock. The income
51474
+ // leg is real and clockwork — 50 `transferInRewards` distributions over
51475
+ // 152.3 days at a 3.11-day cadence, 12.19 % APR, which is what DefiLlama's
51476
+ // 15.58 % and Saturn's "11 %+" both measure — while the vault's whole life
51477
+ // returned **+3.73 % with a −22.82 % max drawdown**. The rate published
51478
+ // here is the REALIZED one; see `saturnFetcher` for why there is no
51479
+ // DefiLlama fallback.
51480
+ //
51481
+ // NOT `secondaryMarketOnly`, and the fork test is why. USDat's own mint is
51482
+ // whitelist-gated (`isWhitelistEnabled()` true, `isAllowedToWrap(<random
51483
+ // EOA>)` false) — but that is a fact about the UNDERLYING, one level below
51484
+ // this row. STAKING is permissionless: `maxDeposit` is `uint256.max`,
51485
+ // `_deposit` consults no allowlist, and a fork deposit from an
51486
+ // unwhitelisted account mints at par. Marking the vault
51487
+ // `secondaryMarketOnly` made `/v1/actions/vaults/deposit` refuse a mint
51488
+ // that works, which is the Brix trap inverted — there a `maxDeposit` of
51489
+ // `uint.max` hid a gate, here a gate on a neighbouring contract hid an
51490
+ // open door. Acquiring the USDat is an ordinary swap (the Curve pool
51491
+ // round-trips 100k at −3 bps with USDat at $0.9997), i.e. a routing
51492
+ // question, not a property of this vault.
51493
+ //
51494
+ // Exit is `request-based` and there is exactly one protocol route:
51495
+ // `requestRedeem(shares, minUsdat)` escrows the shares and mints an
51496
+ // ERC-721 receipt, a `PROCESSOR_ROLE` batch sells STRC, then `claim`.
51497
+ // Measured latency ~24-25 h (Saturn documents 3-7 days) — pinned at 24 h
51498
+ // here and NOT read on-chain, because nothing on the queue publishes it:
51499
+ // it is an operator cadence, not a dial. Verified on-chain 2026-09-10.
51500
+ {
51501
+ reader: "saturn-vault",
51502
+ address: "0xd166337499e176bbc38a1fbd113ab144e5bd2df7",
51503
+ underlying: "0x23238f20b894f29041f48d88ee91131c395aaa71",
51504
+ // USDat
51505
+ symbol: "sUSDat",
51506
+ brand: "Saturn",
51507
+ solvency: "overcollateralized",
51508
+ description: "Saturn's staking vault: deposited USDat (a dollar backed by tokenized Treasuries) buys Strategy's STRC preferred stock, whose dividend is paid in every three days. Almost all the backing is that one stock, marked to market \u2014 so the share price falls when STRC does, and it has: a ~12% dividend over the first five months still returned only 3.7% annualised, after a 22.8% drawdown. Leaving is a request a Saturn operator settles in about a day by selling STRC, paying what that sale realises rather than the share price on the day you asked.",
51509
+ decimals: 18,
51510
+ underlyingDecimals: 6,
51511
+ isRebasing: false,
51512
+ isMintable: true,
51513
+ withdrawalMode: "request-based",
51514
+ withdrawalCooldownSeconds: 86400,
51515
+ withdrawQueue: "0x4bc9fec04f0f95e9b42a3ef18f3c96fb57923d2e",
51516
+ yieldFetcher: saturnFetcher,
51517
+ yieldKey: SUSDAT_KEY
51518
+ },
51258
51519
  // ---- Strata (docs.strata.markets) — senior/junior risk tranches ----
51259
51520
  //
51260
51521
  // Six CDO markets, twelve ERC-4626 tranche tokens, all Ethereum.
@@ -51263,7 +51524,8 @@ var SINGLE_CHAIN_ENTRIES = {
51263
51524
  // the senior earns a benchmark-floored rate (its `maxDeposit` is
51264
51525
  // coverage-cap-gated), the junior takes the residual — levered
51265
51526
  // upside AND first-loss capital (jrUSDat marked down to ~0.36
51266
- // absorbing the 2026-07 USDat depeg; junior redemptions pause when
51527
+ // absorbing the 2026-06/07 sUSDat drawdown the SATURN VAULT fell
51528
+ // 22.8 %, USDat itself never lost its peg; junior redemptions pause when
51267
51529
  // senior coverage drops below the market's minimum). Exits are
51268
51530
  // two-legged and both escrow through the market's cooldown
51269
51531
  // contracts, claimed via `finalize`: redeeming into the collateral
@@ -51427,7 +51689,7 @@ var SINGLE_CHAIN_ENTRIES = {
51427
51689
  symbol: "srUSDat",
51428
51690
  solvency: "tranched-senior",
51429
51691
  brand: "Strata",
51430
- description: "Strata's senior tranche over Saturn USDat (a Strategy-preferred-stock-backed dollar): fixed yield at 65% of the STRC dividend rate, junior-protected \u2014 the senior held its rate straight through the 2026-07 USDat depeg that the junior absorbed. Exits claim through cooldown contracts (the sUSDat leg effectively instant) minus a 0\u20135 bps fee.",
51692
+ description: "Strata's senior tranche over Saturn USDat (a Strategy-preferred-stock-backed dollar): fixed yield at 65% of the STRC dividend rate, junior-protected \u2014 the senior held its rate straight through the 2026-06/07 sUSDat drawdown that the junior absorbed. Exits claim through cooldown contracts (the sUSDat leg effectively instant) minus a 0\u20135 bps fee.",
51431
51693
  decimals: 18,
51432
51694
  underlyingDecimals: 6,
51433
51695
  isRebasing: false,
@@ -51444,7 +51706,7 @@ var SINGLE_CHAIN_ENTRIES = {
51444
51706
  symbol: "jrUSDat",
51445
51707
  solvency: "tranched-junior",
51446
51708
  brand: "Strata",
51447
- description: "Strata's junior tranche over Saturn USDat \u2014 first-loss capital that proved it: the 2026-07 USDat collateral depeg marked jrUSDat down to ~0.36 while the senior stayed whole, and its trailing APR is depeg-recovery-inflated. Exits claim through cooldown contracts and pause while senior coverage is below the market minimum.",
51709
+ description: "Strata's junior tranche over Saturn USDat \u2014 first-loss capital that proved it: the 2026-06/07 drawdown in the collateral \u2014 Saturn's sUSDat vault, which is marked to Strategy's STRC preferred stock and fell 22.8%; USDat itself held its peg \u2014 marked jrUSDat down to ~0.36 while the senior stayed whole, and its trailing APR is recovery-inflated. Exits claim through cooldown contracts and pause while senior coverage is below the market minimum.",
51448
51710
  decimals: 18,
51449
51711
  underlyingDecimals: 6,
51450
51712
  isRebasing: false,
@@ -52441,6 +52703,10 @@ var SAVINGS_REGISTRY = (() => {
52441
52703
  if (!out[chainId]) out[chainId] = [];
52442
52704
  out[chainId].push(...entries);
52443
52705
  }
52706
+ for (const [chainId, entries] of Object.entries(VENUS_HUB_ENTRIES)) {
52707
+ if (!out[chainId]) out[chainId] = [];
52708
+ out[chainId].push(...entries);
52709
+ }
52444
52710
  return out;
52445
52711
  })();
52446
52712
  var savingsBalanceKind = (chainId, address) => {
@@ -64074,9 +64340,24 @@ var queuedRoute = (i) => ({
64074
64340
  kind: "queued",
64075
64341
  label: asyncLabel(i.withdrawalCooldownSeconds),
64076
64342
  settlement: "async",
64077
- waitSeconds: i.withdrawalCooldownSeconds
64343
+ waitSeconds: i.withdrawalCooldownSeconds,
64344
+ ...i.exitMinAmount !== void 0 ? {
64345
+ minAmount: i.exitMinAmount,
64346
+ minAmountFormatted: i.exitMinAmountFormatted
64347
+ } : {}
64348
+ });
64349
+ var marketRoute = () => ({
64350
+ id: "market",
64351
+ kind: "market",
64352
+ label: "Sell on the market",
64353
+ settlement: "market",
64354
+ description: "The protocol's own mint and redeem are permissioned, so for a holder without that permission this is the route: sell the share token at whatever the book bids, with price impact that grows with size. It fills at the MARKET price, which is not the row's `exchangeRate` \u2014 that stays the NAV \u2014 so the leg must be built with a slippage bound."
64078
64355
  });
64079
64356
  var deriveExitRoutes = (i) => {
64357
+ const routes2 = deriveProtocolExitRoutes(i);
64358
+ return i.secondaryMarketOnly ? [...routes2, marketRoute()] : routes2;
64359
+ };
64360
+ var deriveProtocolExitRoutes = (i) => {
64080
64361
  switch (i.withdrawalMode) {
64081
64362
  // The instant leg pays the fee; the queue pays at par. That is the
64082
64363
  // convention `SavingsVault.withdrawFeeBps` already documents — and
@@ -68481,6 +68762,166 @@ var YieldBasisAmmReadAbi = [
68481
68762
  }
68482
68763
  ];
68483
68764
 
68765
+ // src/vaults/savings/abis/venusHub.ts
68766
+ var VenusHubReadAbi = [
68767
+ {
68768
+ name: "maxDeposit",
68769
+ type: "function",
68770
+ stateMutability: "view",
68771
+ inputs: [{ type: "address" }],
68772
+ outputs: [{ type: "uint256" }]
68773
+ },
68774
+ {
68775
+ name: "hubPaused",
68776
+ type: "function",
68777
+ stateMutability: "view",
68778
+ inputs: [],
68779
+ outputs: [{ type: "bool" }]
68780
+ },
68781
+ {
68782
+ name: "maxWithdrawalSize",
68783
+ type: "function",
68784
+ stateMutability: "view",
68785
+ inputs: [],
68786
+ outputs: [{ type: "uint256" }]
68787
+ },
68788
+ {
68789
+ name: "redeemFeeBps",
68790
+ type: "function",
68791
+ stateMutability: "view",
68792
+ inputs: [],
68793
+ outputs: [{ type: "uint16" }]
68794
+ },
68795
+ {
68796
+ name: "registeredYieldGroups",
68797
+ type: "function",
68798
+ stateMutability: "view",
68799
+ inputs: [],
68800
+ outputs: [{ type: "address[]" }]
68801
+ }
68802
+ ];
68803
+ var VenusYieldGroupReadAbi = [
68804
+ {
68805
+ name: "maxWithdraw",
68806
+ type: "function",
68807
+ stateMutability: "view",
68808
+ inputs: [],
68809
+ outputs: [{ type: "uint256" }]
68810
+ },
68811
+ {
68812
+ name: "totalAssets",
68813
+ type: "function",
68814
+ stateMutability: "view",
68815
+ inputs: [],
68816
+ outputs: [{ type: "uint256" }]
68817
+ },
68818
+ {
68819
+ name: "spotAPYBps",
68820
+ type: "function",
68821
+ stateMutability: "view",
68822
+ inputs: [],
68823
+ outputs: [{ type: "uint64" }]
68824
+ },
68825
+ {
68826
+ name: "blocksPerYear",
68827
+ type: "function",
68828
+ stateMutability: "view",
68829
+ inputs: [],
68830
+ outputs: [{ type: "uint256" }]
68831
+ },
68832
+ {
68833
+ name: "resources",
68834
+ type: "function",
68835
+ stateMutability: "view",
68836
+ inputs: [],
68837
+ outputs: [{ type: "address[]" }]
68838
+ }
68839
+ ];
68840
+ var VenusComptrollerRewardsAbi = [
68841
+ {
68842
+ name: "venusSupplySpeeds",
68843
+ type: "function",
68844
+ stateMutability: "view",
68845
+ inputs: [{ type: "address" }],
68846
+ outputs: [{ type: "uint256" }]
68847
+ },
68848
+ {
68849
+ name: "oracle",
68850
+ type: "function",
68851
+ stateMutability: "view",
68852
+ inputs: [],
68853
+ outputs: [{ type: "address" }]
68854
+ }
68855
+ ];
68856
+ var VenusResilientOracleAbi = [
68857
+ {
68858
+ name: "getPrice",
68859
+ type: "function",
68860
+ stateMutability: "view",
68861
+ inputs: [{ type: "address" }],
68862
+ outputs: [{ type: "uint256" }]
68863
+ },
68864
+ {
68865
+ name: "getUnderlyingPrice",
68866
+ type: "function",
68867
+ stateMutability: "view",
68868
+ inputs: [{ type: "address" }],
68869
+ outputs: [{ type: "uint256" }]
68870
+ }
68871
+ ];
68872
+ var VTokenSizeReadAbi = [
68873
+ {
68874
+ name: "totalSupply",
68875
+ type: "function",
68876
+ stateMutability: "view",
68877
+ inputs: [],
68878
+ outputs: [{ type: "uint256" }]
68879
+ },
68880
+ {
68881
+ name: "exchangeRateStored",
68882
+ type: "function",
68883
+ stateMutability: "view",
68884
+ inputs: [],
68885
+ outputs: [{ type: "uint256" }]
68886
+ },
68887
+ {
68888
+ name: "comptroller",
68889
+ type: "function",
68890
+ stateMutability: "view",
68891
+ inputs: [],
68892
+ outputs: [{ type: "address" }]
68893
+ }
68894
+ ];
68895
+
68896
+ // src/vaults/savings/abis/saturn.ts
68897
+ var SaturnMinWithdrawalAbi = [
68898
+ {
68899
+ name: "MIN_WITHDRAWAL",
68900
+ type: "function",
68901
+ stateMutability: "view",
68902
+ inputs: [],
68903
+ outputs: [{ name: "", type: "uint256" }]
68904
+ }
68905
+ ];
68906
+ var SaturnDepositFeeAbi = [
68907
+ {
68908
+ name: "depositFeeBps",
68909
+ type: "function",
68910
+ stateMutability: "view",
68911
+ inputs: [],
68912
+ outputs: [{ name: "", type: "uint256" }]
68913
+ }
68914
+ ];
68915
+ var SaturnPreviewDepositAbi = [
68916
+ {
68917
+ name: "previewDeposit",
68918
+ type: "function",
68919
+ stateMutability: "view",
68920
+ inputs: [{ name: "assets", type: "uint256" }],
68921
+ outputs: [{ name: "", type: "uint256" }]
68922
+ }
68923
+ ];
68924
+
68484
68925
  // src/vaults/savings/readers/erc4626Idle.ts
68485
68926
  var readerErc4626Idle = (entry) => {
68486
68927
  const shareUnit = 10n ** BigInt(entry.decimals);
@@ -68913,6 +69354,208 @@ var readerNativeWnlp = (entry) => {
68913
69354
  };
68914
69355
  };
68915
69356
 
69357
+ // src/vaults/savings/readers/saturn.ts
69358
+ var readerSaturnVault = (entry) => {
69359
+ const shareUnit = 10n ** BigInt(entry.decimals);
69360
+ const underlyingUnit = 10n ** BigInt(entry.underlyingDecimals ?? entry.decimals);
69361
+ return {
69362
+ calls: [
69363
+ { address: entry.address, name: "totalAssets", params: [] },
69364
+ { address: entry.address, name: "totalSupply", params: [] },
69365
+ { address: entry.address, name: "convertToAssets", params: [shareUnit] },
69366
+ {
69367
+ address: entry.address,
69368
+ name: "previewDeposit",
69369
+ params: [underlyingUnit]
69370
+ },
69371
+ { address: entry.address, name: "depositFeeBps", params: [] },
69372
+ { address: entry.address, name: "MIN_WITHDRAWAL", params: [] }
69373
+ ],
69374
+ abis: [
69375
+ Erc4626ReadAbi2,
69376
+ TotalSupplyAbi2,
69377
+ Erc4626ReadAbi2,
69378
+ SaturnPreviewDepositAbi,
69379
+ SaturnDepositFeeAbi,
69380
+ SaturnMinWithdrawalAbi
69381
+ ],
69382
+ parse: ([assets, supply, rate, previewShares, feeBps, minWithdrawal]) => {
69383
+ const totalAssets = toBigInt15(assets);
69384
+ const totalSupply = toBigInt15(supply);
69385
+ const convertToAssetsRaw = toBigInt15(rate);
69386
+ if (totalAssets === void 0 || totalSupply === void 0 || convertToAssetsRaw === void 0) {
69387
+ return void 0;
69388
+ }
69389
+ const entryShares = toBigInt15(previewShares);
69390
+ const depositFeeBps = toBigInt15(feeBps);
69391
+ const exitMinAmount = toBigInt15(minWithdrawal);
69392
+ return {
69393
+ totalAssets,
69394
+ totalSupply,
69395
+ exchangeRate: convertToAssetsRaw * ONE_E1814 / underlyingUnit,
69396
+ // Shares minted for ONE underlying unit, net of the fee. Equals the
69397
+ // derived `1/exchangeRate` while the dial is 0, and diverges the
69398
+ // moment it is not.
69399
+ convertToShares: entryShares,
69400
+ depositFeeBps: depositFeeBps !== void 0 ? Number(depositFeeBps) : void 0,
69401
+ exitMinAmount
69402
+ };
69403
+ }
69404
+ };
69405
+ };
69406
+
69407
+ // src/vaults/savings/readers/venusHub.ts
69408
+ var NEUTRAL_PROBE2 = "0x000000000000000000000000000000000000dead";
69409
+ var BPS_TO_PCT = 100;
69410
+ var readerVenusHub = (entry) => {
69411
+ const shareUnit = 10n ** BigInt(entry.decimals);
69412
+ const underlyingUnit = 10n ** BigInt(entry.underlyingDecimals ?? entry.decimals);
69413
+ const cfg = entry.venusHub;
69414
+ const groups = cfg?.yieldGroups ?? [];
69415
+ const coreGroup = cfg?.core?.yieldGroup;
69416
+ const calls = [
69417
+ { address: entry.address, name: "totalAssets", params: [] },
69418
+ { address: entry.address, name: "totalSupply", params: [] },
69419
+ { address: entry.address, name: "convertToAssets", params: [shareUnit] },
69420
+ { address: entry.address, name: "maxDeposit", params: [NEUTRAL_PROBE2] },
69421
+ { address: entry.address, name: "hubPaused", params: [] },
69422
+ { address: entry.address, name: "maxWithdrawalSize", params: [] },
69423
+ { address: entry.address, name: "redeemFeeBps", params: [] },
69424
+ { address: entry.underlying, name: "balanceOf", params: [entry.address] }
69425
+ ];
69426
+ const abis = [
69427
+ Erc4626ReadAbi2,
69428
+ TotalSupplyAbi2,
69429
+ Erc4626ReadAbi2,
69430
+ VenusHubReadAbi,
69431
+ VenusHubReadAbi,
69432
+ VenusHubReadAbi,
69433
+ VenusHubReadAbi,
69434
+ BalanceOfAbi
69435
+ ];
69436
+ for (const group of groups) {
69437
+ calls.push({ address: group, name: "maxWithdraw", params: [] });
69438
+ calls.push({ address: group, name: "totalAssets", params: [] });
69439
+ calls.push({ address: group, name: "spotAPYBps", params: [] });
69440
+ abis.push(
69441
+ VenusYieldGroupReadAbi,
69442
+ VenusYieldGroupReadAbi,
69443
+ VenusYieldGroupReadAbi
69444
+ );
69445
+ }
69446
+ const emissionCallCount = cfg?.core ? 6 : 0;
69447
+ if (cfg?.core) {
69448
+ const { yieldGroup, vToken, comptroller, oracle, rewardToken } = cfg.core;
69449
+ calls.push({ address: yieldGroup, name: "blocksPerYear", params: [] });
69450
+ calls.push({
69451
+ address: comptroller,
69452
+ name: "venusSupplySpeeds",
69453
+ params: [vToken]
69454
+ });
69455
+ calls.push({ address: oracle, name: "getPrice", params: [rewardToken] });
69456
+ calls.push({
69457
+ address: oracle,
69458
+ name: "getUnderlyingPrice",
69459
+ params: [vToken]
69460
+ });
69461
+ calls.push({ address: vToken, name: "totalSupply", params: [] });
69462
+ calls.push({ address: vToken, name: "exchangeRateStored", params: [] });
69463
+ abis.push(
69464
+ VenusYieldGroupReadAbi,
69465
+ VenusComptrollerRewardsAbi,
69466
+ VenusResilientOracleAbi,
69467
+ VenusResilientOracleAbi,
69468
+ VTokenSizeReadAbi,
69469
+ VTokenSizeReadAbi
69470
+ );
69471
+ }
69472
+ return {
69473
+ calls,
69474
+ abis,
69475
+ parse: (slice2) => {
69476
+ const totalAssets = toBigInt15(slice2[0]);
69477
+ const totalSupply = toBigInt15(slice2[1]);
69478
+ const convertToAssetsRaw = toBigInt15(slice2[2]);
69479
+ if (totalAssets === void 0 || totalSupply === void 0 || convertToAssetsRaw === void 0) {
69480
+ return void 0;
69481
+ }
69482
+ const paused = slice2[4] === true;
69483
+ const maxWithdrawalSize = toBigInt15(slice2[5]);
69484
+ const redeemFeeBps = toBigInt15(slice2[6]);
69485
+ const idle = toBigInt15(slice2[7]);
69486
+ const depositCapacity = toBigInt15(slice2[3]);
69487
+ let groupLiquid = 0n;
69488
+ let weightedBps = 0n;
69489
+ let rateWeight = 0n;
69490
+ let coreGroupAssets = 0n;
69491
+ let groupsOk = groups.length > 0;
69492
+ for (let i = 0; i < groups.length; i++) {
69493
+ const base = 8 + i * 3;
69494
+ const liquid = toBigInt15(slice2[base]);
69495
+ const assets = toBigInt15(slice2[base + 1]);
69496
+ const apyBps = toBigInt15(slice2[base + 2]);
69497
+ if (liquid === void 0 || assets === void 0 || apyBps === void 0) {
69498
+ groupsOk = false;
69499
+ continue;
69500
+ }
69501
+ if (groups[i] === coreGroup) coreGroupAssets = assets;
69502
+ groupLiquid += liquid;
69503
+ weightedBps += apyBps * assets;
69504
+ rateWeight += assets;
69505
+ }
69506
+ let instantRedeemCapacity;
69507
+ if (groupsOk && idle !== void 0) {
69508
+ const aggregate = groupLiquid + idle;
69509
+ instantRedeemCapacity = maxWithdrawalSize !== void 0 && maxWithdrawalSize < aggregate ? maxWithdrawalSize : aggregate;
69510
+ }
69511
+ const supplyRate = rateWeight > 0n ? Number(weightedBps * 1000000n / rateWeight) / 1e6 / BPS_TO_PCT : void 0;
69512
+ return {
69513
+ totalAssets,
69514
+ totalSupply,
69515
+ exchangeRate: convertToAssetsRaw * ONE_E1814 / underlyingUnit,
69516
+ ...supplyRate !== void 0 ? { supplyRate } : {},
69517
+ ...instantRedeemCapacity !== void 0 ? {
69518
+ instantRedeemCapacity: paused ? 0n : instantRedeemCapacity,
69519
+ instantRedeemEnabled: !paused,
69520
+ // Retained in the vault rather than paid out, and 0 on every
69521
+ // live Hub — but it IS deducted from a redeemer's payout, so
69522
+ // it belongs on the same field every other two-legged row uses.
69523
+ withdrawFeeBps: redeemFeeBps !== void 0 ? Number(redeemFeeBps) : 0
69524
+ } : {},
69525
+ ...depositCapacity !== void 0 ? { depositCapacity } : {},
69526
+ ...cfg?.core ? {
69527
+ strandedRewardsRate: parseStrandedRewards(
69528
+ slice2,
69529
+ calls.length - emissionCallCount,
69530
+ coreGroupAssets,
69531
+ totalAssets
69532
+ )
69533
+ } : {}
69534
+ };
69535
+ }
69536
+ };
69537
+ };
69538
+ var parseStrandedRewards = (slice2, base, coreGroupAssets, hubTotalAssets) => {
69539
+ const blocksPerYear = toBigInt15(slice2[base]);
69540
+ const supplySpeed = toBigInt15(slice2[base + 1]);
69541
+ const rewardPrice = toBigInt15(slice2[base + 2]);
69542
+ const underlyingPrice = toBigInt15(slice2[base + 3]);
69543
+ const vTokenSupply = toBigInt15(slice2[base + 4]);
69544
+ const exchangeRateStored = toBigInt15(slice2[base + 5]);
69545
+ if (blocksPerYear === void 0 || supplySpeed === void 0 || rewardPrice === void 0 || underlyingPrice === void 0 || vTokenSupply === void 0 || exchangeRateStored === void 0) {
69546
+ return void 0;
69547
+ }
69548
+ if (supplySpeed === 0n) return 0;
69549
+ const rewardsPerYearUsd = supplySpeed * blocksPerYear * rewardPrice;
69550
+ const suppliedRaw = vTokenSupply * exchangeRateStored / ONE_E1814;
69551
+ const suppliedUsd = suppliedRaw * underlyingPrice;
69552
+ if (suppliedUsd === 0n || hubTotalAssets === 0n) return void 0;
69553
+ const marketAprPct = Number(rewardsPerYearUsd * 1000000000n / suppliedUsd) / 1e9;
69554
+ const hubShare = Number(coreGroupAssets * 1000000000n / hubTotalAssets) / 1e9;
69555
+ const scale3 = hubShare > 1 ? 1 : hubShare;
69556
+ return marketAprPct * scale3 * 100;
69557
+ };
69558
+
68916
69559
  // src/vaults/savings/readers/vesperPool.ts
68917
69560
  var readerVesperPool = (entry) => {
68918
69561
  const underlyingUnit = 10n ** BigInt(entry.underlyingDecimals ?? entry.decimals);
@@ -69046,6 +69689,10 @@ var buildReader2 = (entry) => {
69046
69689
  return readerWrenNav(entry);
69047
69690
  case "vesper-pool":
69048
69691
  return readerVesperPool(entry);
69692
+ case "venus-hub":
69693
+ return readerVenusHub(entry);
69694
+ case "saturn-vault":
69695
+ return readerSaturnVault(entry);
69049
69696
  case "erc4626-cooldown":
69050
69697
  return readerErc4626Cooldown(entry);
69051
69698
  case "erc4626-idle":
@@ -69098,7 +69745,7 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
69098
69745
  const underlyingLc = entry.underlying.toLowerCase();
69099
69746
  const asset = tokenList[underlyingLc];
69100
69747
  const priceUsd = prices[underlyingLc];
69101
- const supplyRate = aprByAddress[addressLc] ?? 0;
69748
+ const supplyRate = state.supplyRate ?? aprByAddress[addressLc] ?? 0;
69102
69749
  const rewardsRate = 0;
69103
69750
  const depositRate = supplyRate + rewardsRate;
69104
69751
  const shareDec = entry.decimals;
@@ -69120,7 +69767,7 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
69120
69767
  Number(liquidityAmount * 1000000n / state.totalAssets) / 1e6
69121
69768
  ) : 1;
69122
69769
  const convertToAssets = state.exchangeRate * underlyingUnit / ONE_E1815;
69123
- const convertToShares = state.exchangeRate > 0n ? ONE_E1815 * shareUnit / state.exchangeRate : 0n;
69770
+ const convertToShares = state.convertToShares ?? (state.exchangeRate > 0n ? ONE_E1815 * shareUnit / state.exchangeRate : 0n);
69124
69771
  const depositCapacity = state.depositCapacity?.toString();
69125
69772
  const depositCapacityFormatted = state.depositCapacity !== void 0 ? Number(state.depositCapacity) / 10 ** underlyingDec : void 0;
69126
69773
  const depositCapacityUsd = depositCapacityFormatted !== void 0 && priceUsd !== void 0 ? depositCapacityFormatted * priceUsd : void 0;
@@ -69156,6 +69803,9 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
69156
69803
  supplyRate,
69157
69804
  rewardsRate,
69158
69805
  depositRate,
69806
+ // NOT part of `depositRate` — it is the incentive the vault's position
69807
+ // earns and the depositor does not. See the field's docstring.
69808
+ strandedRewardsRate: state.strandedRewardsRate,
69159
69809
  // Opt-IN, not opt-out: a new bespoke reader exists precisely
69160
69810
  // because its token is not a conforming vault, so the default for
69161
69811
  // an unlisted reader must be `false`. `erc4626-idle`,
@@ -69164,7 +69814,11 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
69164
69814
  // limit view / the exit lock), so they count; Native's wNLP and Re's
69165
69815
  // NAV-oracle tokens revert on
69166
69816
  // `asset()`/`totalAssets()`/`convertToAssets()` and do not.
69167
- isErc4626: entry.reader === void 0 || entry.reader === "erc4626" || entry.reader === "erc4626-cooldown" || entry.reader === "erc4626-idle" || entry.reader === "erc4626-withdraw-limit" || // hbfUSD / pbfUSD ARE conforming 4626 the bespoke reader exists for
69817
+ isErc4626: entry.reader === void 0 || entry.reader === "erc4626" || entry.reader === "erc4626-cooldown" || entry.reader === "erc4626-idle" || entry.reader === "erc4626-withdraw-limit" || // Venus's Liquidity Hub IS a conforming 4626 on every leg
69818
+ // (`deposit(assets, receiver)`, `redeem(shares, receiver, owner)`);
69819
+ // the bespoke reader exists for the FRV lock, the rate blend and the
69820
+ // emission read, not because the standard surface is missing.
69821
+ entry.reader === "venus-hub" || // hbfUSD / pbfUSD ARE conforming 4626 — the bespoke reader exists for
69168
69822
  // the epoch ledger and the share-denominated supply cap, not because
69169
69823
  // the standard surface is missing. bfBTC (`bitfi-bfbtc`) is the
69170
69824
  // opposite and correctly falls through to `false`.
@@ -69180,6 +69834,7 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
69180
69834
  // queue window is per-asset and governance-mutable.
69181
69835
  withdrawalCooldownSeconds: state.withdrawalCooldownSeconds ?? entry.withdrawalCooldownSeconds,
69182
69836
  withdrawFeeBps: state.withdrawFeeBps,
69837
+ depositFeeBps: state.depositFeeBps,
69183
69838
  // Term-sheet inputs that no reader can derive — see the registry's
69184
69839
  // docstrings. Passed through verbatim so the sheet can stop hardcoding
69185
69840
  // "compounds per second" and "needs an approval" for every vault.
@@ -69204,7 +69859,13 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
69204
69859
  withdrawalCooldownSeconds: state.withdrawalCooldownSeconds ?? entry.withdrawalCooldownSeconds,
69205
69860
  liquidity: liquidityRaw,
69206
69861
  liquidityFormatted,
69207
- liquidityUsd
69862
+ liquidityUsd,
69863
+ // The floor that decides whether a single-route exit is reachable.
69864
+ exitMinAmount: state.exitMinAmount?.toString(),
69865
+ exitMinAmountFormatted: state.exitMinAmount !== void 0 ? Number(state.exitMinAmount) / 10 ** underlyingDec : void 0,
69866
+ // Adds the `market` leg — the only route a holder without the
69867
+ // protocol's mint/redeem permission actually has.
69868
+ secondaryMarketOnly: entry.secondaryMarketOnly
69208
69869
  }),
69209
69870
  resolveSelfOnly(chainId, entry.address)
69210
69871
  ),
@@ -70259,8 +70920,20 @@ var VOLATILE_VAULT_OVERRIDES = /* @__PURE__ */ new Set([
70259
70920
  // yb-cbBTC
70260
70921
  "1-0x771f7290428d830ecd41e980745c327e507823ec",
70261
70922
  // yb-tBTC
70262
- "1-0x2b9c9f3bdceb5d8e36a4704f08a78fca53343cea"
70923
+ "1-0x2b9c9f3bdceb5d8e36a4704f08a78fca53343cea",
70263
70924
  // yb-WETH
70925
+ // Saturn sUSDat — a savings vault whose assets are 96.5 % Strategy's STRC
70926
+ // preferred stock, held outright and MARKED to an oracle
70927
+ // (`totalAssets = usdatBalance + (strcBalance − unvested) × price`). Unlike
70928
+ // Yield Basis this one has a real, clockwork income leg — 50
70929
+ // `transferInRewards` distributions on a 3.11-day cadence, 12.19 % APR
70930
+ // measured over 152 days, which is what DefiLlama's 15.58 % reports — and it
70931
+ // is still not a yield-bearing row, because the mark moves further than the
70932
+ // coupon does. Over the vault's whole life: +3.73 % realized APR, −22.82 %
70933
+ // max drawdown (1.00954 on 2026-05-15 → 0.77915 on 2026-06-28), 33 % of
70934
+ // two-day samples negative. See SATURN.md.
70935
+ "1-0xd166337499e176bbc38a1fbd113ab144e5bd2df7"
70936
+ // sUSDat
70264
70937
  ]);
70265
70938
  var STABLECOIN_SYMBOLS = /* @__PURE__ */ new Set([
70266
70939
  // USD majors
@@ -70356,6 +71029,12 @@ var STABLECOIN_SYMBOLS = /* @__PURE__ */ new Set([
70356
71029
  "USG",
70357
71030
  "BOB"
70358
71031
  ]);
71032
+ var STABLECOIN_UNDERLYING_OVERRIDES = /* @__PURE__ */ new Set([
71033
+ // United Stables (`U`) — a USD stablecoin on BNB Chain, a Venus Core market
71034
+ // and the underlying of the vhU Liquidity Hub. Priced at $0.999 by Venus's
71035
+ // own ResilientOracle.
71036
+ "56-0xce24439f2d9c6a2289f741120fe202248b666666"
71037
+ ]);
70359
71038
  var normalizeSymbol = (s) => (s ?? "").trim().toUpperCase();
70360
71039
  var isStablecoinSymbol = (symbol) => {
70361
71040
  const s = normalizeSymbol(symbol);
@@ -70366,7 +71045,8 @@ var isStablecoinSymbol = (symbol) => {
70366
71045
  var classifyVault = (input) => {
70367
71046
  const key3 = `${input.chainId}-${input.address.toLowerCase()}`;
70368
71047
  const yieldProfile2 = VOLATILE_VAULT_OVERRIDES.has(key3) || VOLATILE_PROVIDERS.has(input.provider) ? "volatile" : "yield-bearing";
70369
- const denomination2 = isStablecoinSymbol(input.underlyingSymbol) ? "stable" : "volatile";
71048
+ const underlyingKey = input.underlyingAddress !== void 0 ? `${input.chainId}-${input.underlyingAddress.toLowerCase()}` : void 0;
71049
+ const denomination2 = underlyingKey !== void 0 && STABLECOIN_UNDERLYING_OVERRIDES.has(underlyingKey) || isStablecoinSymbol(input.underlyingSymbol) ? "stable" : "volatile";
70370
71050
  return { yieldProfile: yieldProfile2, denomination: denomination2 };
70371
71051
  };
70372
71052
  var stampVaultClassification = (data, chainId, tokenList = {}) => {
@@ -70387,7 +71067,8 @@ var stampVaultClassification = (data, chainId, tokenList = {}) => {
70387
71067
  provider,
70388
71068
  chainId,
70389
71069
  address: v.address,
70390
- underlyingSymbol: v.asset?.symbol ?? v.symbol
71070
+ underlyingSymbol: v.asset?.symbol ?? v.symbol,
71071
+ underlyingAddress: v.underlying
70391
71072
  });
70392
71073
  v.yieldProfile = c.yieldProfile;
70393
71074
  v.denomination = c.denomination;
@@ -72118,7 +72799,7 @@ var readVaultSharePrices = async (chainId, addresses, multicallRetry) => {
72118
72799
  };
72119
72800
 
72120
72801
  // src/vaults/yield/annualize.ts
72121
- var YEAR_SECONDS12 = 365 * 24 * 60 * 60;
72802
+ var YEAR_SECONDS13 = 365 * 24 * 60 * 60;
72122
72803
  var SCALE = 10n ** 18n;
72123
72804
  var appendSnapshot = (points, snap, options) => {
72124
72805
  const maxPoints = options?.maxPoints ?? 90;
@@ -72147,7 +72828,7 @@ var computeVaultApr = (points, options) => {
72147
72828
  if (pThen === 0n) return void 0;
72148
72829
  const ratioScaled = BigInt(now.p) * SCALE / pThen;
72149
72830
  const ratio = Number(ratioScaled) / 1e18;
72150
- const apr = (ratio - 1) * (YEAR_SECONDS12 / windowSeconds);
72831
+ const apr = (ratio - 1) * (YEAR_SECONDS13 / windowSeconds);
72151
72832
  return {
72152
72833
  apr,
72153
72834
  sharePriceNow: now.p,