@perena/vault-sdk 1.0.23 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +306 -149
  2. package/dist/index.js +1262 -233
  3. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -250,9 +250,9 @@ var require_meta = __commonJS({
250
250
  exports2.toCustomAccountMeta = toCustomAccountMeta;
251
251
  exports2.toCustomAccountMetaFromWeb3AccountMeta = toCustomAccountMetaFromWeb3AccountMeta;
252
252
  var roles_1 = require_roles();
253
- function toCustomAccountMeta(address10, isWritable, requiredAtaDetails, isSigner) {
253
+ function toCustomAccountMeta(address12, isWritable, requiredAtaDetails, isSigner) {
254
254
  const role = (0, roles_1.getAccountRole)(isWritable ?? false, isSigner ?? false);
255
- return { address: address10, role, isRequiredAta: requiredAtaDetails };
255
+ return { address: address12, role, isRequiredAta: requiredAtaDetails };
256
256
  }
257
257
  function toCustomAccountMetaFromWeb3AccountMeta(web3AccountMeta) {
258
258
  return toCustomAccountMeta(web3AccountMeta.pubkey.toBase58(), web3AccountMeta.isWritable, void 0, web3AccountMeta.isSigner);
@@ -611,12 +611,12 @@ var require_transaction = __commonJS({
611
611
  async function sendVersionedTransaction({ connection, payer, instructions: instructions2, lookupTables }) {
612
612
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
613
613
  const lookupTableAccounts = await fetchLookupTables(connection, lookupTables);
614
- const message = new web3_js_1.TransactionMessage({
614
+ const message2 = new web3_js_1.TransactionMessage({
615
615
  payerKey: payer.publicKey,
616
616
  recentBlockhash: blockhash,
617
617
  instructions: instructions2
618
618
  }).compileToV0Message(lookupTableAccounts);
619
- const tx = new web3_js_1.VersionedTransaction(message);
619
+ const tx = new web3_js_1.VersionedTransaction(message2);
620
620
  tx.sign([payer]);
621
621
  const signature = await connection.sendRawTransaction(tx.serialize(), {
622
622
  skipPreflight: true
@@ -1200,8 +1200,8 @@ var require_cpiClient = __commonJS({
1200
1200
  var kit_1 = require("@solana/kit");
1201
1201
  var common_1 = require_dist();
1202
1202
  var constants_1 = require_constants3();
1203
- function account(address10, role) {
1204
- return { address: address10, role };
1203
+ function account(address12, role) {
1204
+ return { address: address12, role };
1205
1205
  }
1206
1206
  function requiredAddress(value, label) {
1207
1207
  if (!value) {
@@ -1290,7 +1290,7 @@ var require_cpiClient = __commonJS({
1290
1290
  });
1291
1291
  const bankAndOracleRemainingAccounts = [
1292
1292
  account(this.accounts.bank, kit_1.AccountRole.READONLY),
1293
- ...this.accounts.oracleAccounts.map((address10) => account(address10, kit_1.AccountRole.READONLY))
1293
+ ...this.accounts.oracleAccounts.map((address12) => account(address12, kit_1.AccountRole.READONLY))
1294
1294
  ];
1295
1295
  return {
1296
1296
  cpiType: params.cpiType ?? common_1.CpiTypes.MARGINFI_WITHDRAW,
@@ -1414,11 +1414,17 @@ __export(index_exports, {
1414
1414
  JupiterPriceSource: () => JupiterPriceSource,
1415
1415
  JupiterSwapBuilder: () => JupiterSwapBuilder,
1416
1416
  KaminoPositionProvider: () => KaminoPositionProvider,
1417
+ LOCAL_PROTOCOL_ADMIN: () => LOCAL_PROTOCOL_ADMIN,
1418
+ LivePriceSource: () => LivePriceSource,
1417
1419
  MAX_PRICE_STALENESS_THRESHOLD_SECS: () => MAX_PRICE_STALENESS_THRESHOLD_SECS,
1418
1420
  ManagerRedepositAssetBuilder: () => ManagerRedepositAssetBuilder,
1419
1421
  ManagerWithdrawAssetBuilder: () => ManagerWithdrawAssetBuilder,
1420
1422
  MarginfiPositionProvider: () => MarginfiPositionProvider,
1421
1423
  MockYieldTracker: () => MockYieldTracker,
1424
+ NEST_API_BASE_URL: () => NEST_API_BASE_URL,
1425
+ NEST_RWA_SHARE_MINT: () => NEST_RWA_SHARE_MINT,
1426
+ NEST_VAULT_SLUG: () => NEST_VAULT_SLUG,
1427
+ NestPriceSource: () => NestPriceSource,
1422
1428
  OracleService: () => OracleService,
1423
1429
  PROGRAM_FEE_EXEMPT_OWNER_WHITELIST: () => PROGRAM_FEE_EXEMPT_OWNER_WHITELIST,
1424
1430
  PROTOCOL_ADMIN: () => PROTOCOL_ADMIN,
@@ -1461,6 +1467,7 @@ __export(index_exports, {
1461
1467
  WithdrawalQueueService: () => WithdrawalQueueService,
1462
1468
  addCashflowUpdate: () => addCashflowUpdate,
1463
1469
  address: () => import_kit10.address,
1470
+ applyEffectiveApy: () => applyEffectiveApy,
1464
1471
  confirmYieldPayment: () => confirmYieldPayment,
1465
1472
  createAccount: () => createAccount,
1466
1473
  createLiveConsensusOracleDeps: () => createLiveConsensusOracleDeps,
@@ -1472,7 +1479,9 @@ __export(index_exports, {
1472
1479
  dateToStr: () => dateToStr,
1473
1480
  defaultKeypairPath: () => defaultKeypairPath,
1474
1481
  deleteAccount: () => deleteAccount,
1482
+ fetchNestTokenPrice: () => fetchNestTokenPrice,
1475
1483
  findSquadsWalletRoute: () => findSquadsWalletRoute,
1484
+ formatSettlementSimulation: () => formatSettlementSimulation,
1476
1485
  fromUiAmount: () => fromUiAmount,
1477
1486
  getAccounts: () => getAccounts,
1478
1487
  getBalance: () => getBalance,
@@ -1493,6 +1502,7 @@ __export(index_exports, {
1493
1502
  resolveSquadsWalletRoute: () => resolveSquadsWalletRoute,
1494
1503
  roundToNextUtcMidnight: () => roundToNextUtcMidnight,
1495
1504
  runLiveConsensusOracle: () => runLiveConsensusOracle,
1505
+ simulateConsensusOracleSettlement: () => simulateConsensusOracleSettlement,
1496
1506
  systemClock: () => systemClock,
1497
1507
  toUiAmount: () => toUiAmount,
1498
1508
  updateAccount: () => updateAccount,
@@ -1511,6 +1521,9 @@ var VAULT_PROGRAM_ID = (0, import_kit.address)(
1511
1521
  );
1512
1522
  var VAULT_PROGRAM_PUBLIC_KEY = new import_web3.PublicKey(VAULT_PROGRAM_ID);
1513
1523
  var PROTOCOL_ADMIN = (0, import_kit.address)(
1524
+ "4jMRBkpWrfhhwFYTwG3o7hmsXQwbJUwdyUX8htB6KwLJ"
1525
+ );
1526
+ var LOCAL_PROTOCOL_ADMIN = (0, import_kit.address)(
1514
1527
  "BQJZAhDnvgSGHjdAbzQEXRBYzSBuWgSYqDzhDnUSRWGR"
1515
1528
  );
1516
1529
  var PROTOCOL_FEE_RECIPIENT = (0, import_kit.address)(
@@ -1522,7 +1535,7 @@ var PROGRAM_FEE_EXEMPT_OWNER_WHITELIST = [
1522
1535
  (0, import_kit.address)("LYC8YiiSzQfPpxUW2tpxfuPKGZwywAJhXKUfDP2B66f")
1523
1536
  ];
1524
1537
  var VAULT_CREATOR_WHITELIST = [
1525
- (0, import_kit.address)("11111111111111111111111111111111")
1538
+ (0, import_kit.address)("4jMRBkpWrfhhwFYTwG3o7hmsXQwbJUwdyUX8htB6KwLJ")
1526
1539
  ];
1527
1540
  var TOKEN_PROGRAM_ID = (0, import_kit.address)(
1528
1541
  import_spl_token.TOKEN_2022_PROGRAM_ID.toBase58()
@@ -1768,8 +1781,7 @@ var IDL = {
1768
1781
  {
1769
1782
  "name": "fee_asset_mint",
1770
1783
  "docs": [
1771
- "Base-asset mint used to pay performance fees on settlement. Must match",
1772
- "an `is_base` holding; choose a mint whose vault ATA has liquidity."
1784
+ "Legacy fee-asset account retained in this instruction's account schema."
1773
1785
  ]
1774
1786
  },
1775
1787
  {
@@ -1832,7 +1844,7 @@ var IDL = {
1832
1844
  {
1833
1845
  "name": "fee_vault",
1834
1846
  "docs": [
1835
- "Per-vault fee-vault PDA: token authority + accounting for accrued fees."
1847
+ "Legacy fee-vault account retained in this instruction's account schema."
1836
1848
  ],
1837
1849
  "writable": true
1838
1850
  },
@@ -1926,84 +1938,18 @@ var IDL = {
1926
1938
  "signer": true
1927
1939
  },
1928
1940
  {
1929
- "name": "vault"
1930
- },
1931
- {
1932
- "name": "fee_asset_mint",
1933
- "docs": [
1934
- "Vault base asset whose fee-vault ATA should be swept. Must match an",
1935
- "`is_base` holding with a fresh price."
1936
- ]
1937
- },
1938
- {
1939
- "name": "fee_vault",
1940
- "docs": [
1941
- "Per-vault fee-vault PDA: token authority + accounting for accrued fees."
1942
- ],
1941
+ "name": "vault",
1943
1942
  "writable": true
1944
1943
  },
1945
1944
  {
1946
- "name": "fee_vault_ata",
1947
- "writable": true,
1948
- "pda": {
1949
- "seeds": [
1950
- {
1951
- "kind": "account",
1952
- "path": "fee_vault"
1953
- },
1954
- {
1955
- "kind": "account",
1956
- "path": "fee_asset_token_program"
1957
- },
1958
- {
1959
- "kind": "account",
1960
- "path": "fee_asset_mint"
1961
- }
1962
- ],
1963
- "program": {
1964
- "kind": "const",
1965
- "value": [
1966
- 140,
1967
- 151,
1968
- 37,
1969
- 143,
1970
- 78,
1971
- 36,
1972
- 137,
1973
- 241,
1974
- 187,
1975
- 61,
1976
- 16,
1977
- 41,
1978
- 20,
1979
- 142,
1980
- 13,
1981
- 131,
1982
- 11,
1983
- 90,
1984
- 19,
1985
- 153,
1986
- 218,
1987
- 255,
1988
- 16,
1989
- 132,
1990
- 4,
1991
- 142,
1992
- 123,
1993
- 216,
1994
- 219,
1995
- 233,
1996
- 248,
1997
- 89
1998
- ]
1999
- }
2000
- }
1945
+ "name": "share_mint",
1946
+ "writable": true
2001
1947
  },
2002
1948
  {
2003
1949
  "name": "fee_collector"
2004
1950
  },
2005
1951
  {
2006
- "name": "fee_collector_fee_asset_ata",
1952
+ "name": "fee_collector_share_ata",
2007
1953
  "writable": true,
2008
1954
  "pda": {
2009
1955
  "seeds": [
@@ -2013,11 +1959,11 @@ var IDL = {
2013
1959
  },
2014
1960
  {
2015
1961
  "kind": "account",
2016
- "path": "fee_asset_token_program"
1962
+ "path": "share_token_program"
2017
1963
  },
2018
1964
  {
2019
1965
  "kind": "account",
2020
- "path": "fee_asset_mint"
1966
+ "path": "share_mint"
2021
1967
  }
2022
1968
  ],
2023
1969
  "program": {
@@ -2063,7 +2009,7 @@ var IDL = {
2063
2009
  "name": "protocol_fee_collector"
2064
2010
  },
2065
2011
  {
2066
- "name": "protocol_fee_collector_fee_asset_ata",
2012
+ "name": "protocol_fee_collector_share_ata",
2067
2013
  "writable": true,
2068
2014
  "pda": {
2069
2015
  "seeds": [
@@ -2073,11 +2019,11 @@ var IDL = {
2073
2019
  },
2074
2020
  {
2075
2021
  "kind": "account",
2076
- "path": "fee_asset_token_program"
2022
+ "path": "share_token_program"
2077
2023
  },
2078
2024
  {
2079
2025
  "kind": "account",
2080
- "path": "fee_asset_mint"
2026
+ "path": "share_mint"
2081
2027
  }
2082
2028
  ],
2083
2029
  "program": {
@@ -2120,7 +2066,7 @@ var IDL = {
2120
2066
  }
2121
2067
  },
2122
2068
  {
2123
- "name": "fee_asset_token_program"
2069
+ "name": "share_token_program"
2124
2070
  },
2125
2071
  {
2126
2072
  "name": "associated_token_program",
@@ -3003,7 +2949,9 @@ var IDL = {
3003
2949
  {
3004
2950
  "name": "share_mint",
3005
2951
  "docs": [
3006
- "Curator-supplied share mint. Its decimals must match `asset_mint`.",
2952
+ "Curator-supplied share mint. Its decimals define the vault accounting",
2953
+ "precision. `asset_mint` may use a different precision, which is stored",
2954
+ "on its holding and handled by holding-price conversion.",
3007
2955
  "Unless `for_migration`, it must have zero supply with mint authority on",
3008
2956
  "the curator; authority is transferred to the vault PDA on success.",
3009
2957
  "Migration uses the legacy bank mint and defers transfer."
@@ -3227,8 +3175,8 @@ var IDL = {
3227
3175
  {
3228
3176
  "name": "fee_vault",
3229
3177
  "docs": [
3230
- "Per-vault fee-vault PDA: token authority + accounting. The mint fee",
3231
- "accrues here and is swept to the fee collector by the permissionless crank."
3178
+ "Legacy fee-vault account retained in this instruction's account schema.",
3179
+ "New fees accrue as pending vault shares."
3232
3180
  ],
3233
3181
  "writable": true
3234
3182
  },
@@ -3522,8 +3470,8 @@ var IDL = {
3522
3470
  {
3523
3471
  "name": "fee_vault",
3524
3472
  "docs": [
3525
- "Per-vault fee-vault PDA: token authority + accounting. The mint fee",
3526
- "accrues here and is swept to the fee collector by the permissionless crank."
3473
+ "Legacy fee-vault account retained in this instruction's account schema.",
3474
+ "New fees accrue as pending vault shares."
3527
3475
  ],
3528
3476
  "writable": true
3529
3477
  },
@@ -4018,8 +3966,8 @@ var IDL = {
4018
3966
  {
4019
3967
  "name": "fee_vault",
4020
3968
  "docs": [
4021
- "Per-vault fee-vault PDA: token authority + accounting. Mint fees",
4022
- "accrue here and are swept by the permissionless fee crank."
3969
+ "Legacy fee-vault account retained in this instruction's account schema.",
3970
+ "New fees accrue as pending vault shares."
4023
3971
  ],
4024
3972
  "writable": true
4025
3973
  },
@@ -4320,8 +4268,8 @@ var IDL = {
4320
4268
  {
4321
4269
  "name": "fee_vault",
4322
4270
  "docs": [
4323
- "Per-vault fee-vault PDA: token authority + accounting. Mint fees",
4324
- "accrue here and are swept by the permissionless fee crank."
4271
+ "Legacy fee-vault account retained in this instruction's account schema.",
4272
+ "New fees accrue as pending vault shares."
4325
4273
  ],
4326
4274
  "writable": true
4327
4275
  },
@@ -5111,8 +5059,8 @@ var IDL = {
5111
5059
  {
5112
5060
  "name": "fee_vault",
5113
5061
  "docs": [
5114
- "Per-vault fee-vault PDA: token authority + accounting. The burn fee accrues",
5115
- "here and is swept to the fee collector by the permissionless crank."
5062
+ "Legacy fee-vault account retained in this instruction's account schema.",
5063
+ "New fees accrue as pending vault shares."
5116
5064
  ],
5117
5065
  "writable": true
5118
5066
  },
@@ -5400,8 +5348,8 @@ var IDL = {
5400
5348
  {
5401
5349
  "name": "fee_vault",
5402
5350
  "docs": [
5403
- "Per-vault fee-vault PDA: token authority + accounting. The burn fee accrues",
5404
- "here and is swept to the fee collector by the permissionless crank."
5351
+ "Legacy fee-vault account retained in this instruction's account schema.",
5352
+ "New fees accrue as pending vault shares."
5405
5353
  ],
5406
5354
  "writable": true
5407
5355
  },
@@ -5695,8 +5643,8 @@ var IDL = {
5695
5643
  {
5696
5644
  "name": "fee_vault",
5697
5645
  "docs": [
5698
- "Per-vault fee-vault PDA: token authority + accounting. The burn fee accrues",
5699
- "here and is swept to the fee collector by the permissionless crank."
5646
+ "Legacy fee-vault account retained in this instruction's account schema.",
5647
+ "New fees accrue as pending vault shares."
5700
5648
  ],
5701
5649
  "writable": true
5702
5650
  },
@@ -6000,8 +5948,8 @@ var IDL = {
6000
5948
  {
6001
5949
  "name": "fee_vault",
6002
5950
  "docs": [
6003
- "Per-vault fee-vault PDA: token authority + accounting. The burn fee accrues",
6004
- "here and is swept to the fee collector by the permissionless crank."
5951
+ "Legacy fee-vault account retained in this instruction's account schema.",
5952
+ "New fees accrue as pending vault shares."
6005
5953
  ],
6006
5954
  "writable": true
6007
5955
  },
@@ -7422,9 +7370,6 @@ var IDL = {
7422
7370
  },
7423
7371
  {
7424
7372
  "name": "idle_bank_tranche",
7425
- "docs": [
7426
- "path rejects initialized state because it cannot represent junior claims."
7427
- ],
7428
7373
  "pda": {
7429
7374
  "seeds": [
7430
7375
  {
@@ -7583,7 +7528,7 @@ var IDL = {
7583
7528
  {
7584
7529
  "name": "yielding_bank_tranche",
7585
7530
  "docs": [
7586
- "state so an active senior-price regime cannot be hidden by omission."
7531
+ "tranche was already consumed by its regular vault migrations."
7587
7532
  ],
7588
7533
  "pda": {
7589
7534
  "seeds": [
@@ -7761,9 +7706,6 @@ var IDL = {
7761
7706
  },
7762
7707
  {
7763
7708
  "name": "vault_tranche_state",
7764
- "docs": [
7765
- "be initialized and consistent with destination.tranching_enabled."
7766
- ],
7767
7709
  "writable": true,
7768
7710
  "pda": {
7769
7711
  "seeds": [
@@ -9787,6 +9729,69 @@ var IDL = {
9787
9729
  }
9788
9730
  ]
9789
9731
  },
9732
+ {
9733
+ "name": "trigger_bank_circuit_breaker",
9734
+ "discriminator": [
9735
+ 250,
9736
+ 236,
9737
+ 165,
9738
+ 211,
9739
+ 181,
9740
+ 241,
9741
+ 74,
9742
+ 84
9743
+ ],
9744
+ "accounts": [
9745
+ {
9746
+ "name": "bank_state",
9747
+ "writable": true,
9748
+ "pda": {
9749
+ "seeds": [
9750
+ {
9751
+ "kind": "const",
9752
+ "value": [
9753
+ 66,
9754
+ 65,
9755
+ 78,
9756
+ 75
9757
+ ]
9758
+ },
9759
+ {
9760
+ "kind": "account",
9761
+ "path": "bank_state"
9762
+ }
9763
+ ]
9764
+ }
9765
+ },
9766
+ {
9767
+ "name": "bank_manager",
9768
+ "writable": true,
9769
+ "signer": true
9770
+ },
9771
+ {
9772
+ "name": "system_program",
9773
+ "address": "11111111111111111111111111111111"
9774
+ },
9775
+ {
9776
+ "name": "token_program",
9777
+ "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
9778
+ }
9779
+ ],
9780
+ "args": [
9781
+ {
9782
+ "name": "is_halted",
9783
+ "type": "bool"
9784
+ },
9785
+ {
9786
+ "name": "is_halted_deposit",
9787
+ "type": "bool"
9788
+ },
9789
+ {
9790
+ "name": "is_halted_withdrawal",
9791
+ "type": "bool"
9792
+ }
9793
+ ]
9794
+ },
9790
9795
  {
9791
9796
  "name": "trigger_vault_circuit_breaker",
9792
9797
  "discriminator": [
@@ -10548,8 +10553,8 @@ var IDL = {
10548
10553
  {
10549
10554
  "name": "destination_fee_vault",
10550
10555
  "docs": [
10551
- "Destination vault's fee-vault PDA: the mint fee accrues here and is swept",
10552
- "to the fee collector by the permissionless crank."
10556
+ "Legacy fee-vault account retained in this instruction's account schema.",
10557
+ "New fees accrue as pending vault shares."
10553
10558
  ],
10554
10559
  "writable": true
10555
10560
  },
@@ -11866,21 +11871,11 @@ var IDL = {
11866
11871
  {
11867
11872
  "name": "FeeVault",
11868
11873
  "docs": [
11869
- "Per-vault fee custody + accounting account.",
11870
- "",
11871
- "The PDA is both the token authority over the fee-asset ATAs that physically",
11872
- "hold accrued fees and the ledger of what is owed to whom. All four fee types",
11873
- "\u2014 mint, burn, performance, and protocol \u2014 accrue here.",
11874
- "",
11875
- "Ledger amounts (`*_owed` / `*_collected`) are denominated in the vault's",
11876
- "**accounting unit** (the same unit as TVL / holding prices), not raw token",
11877
- "units. Token custody may still be split across ATAs for different base-asset",
11878
- "mints; the permissionless fee crank converts each ATA's balance to accounting",
11879
- "value via that mint's fresh holding price, pays out, and reduces these",
11880
- "counters by the accounting value cleared.",
11874
+ "Legacy per-vault fee custody account.",
11881
11875
  "",
11882
- "Mint/burn/performance go to `vault.roles.fee_collector`, protocol goes to the",
11883
- "hardcoded protocol fee recipient."
11876
+ "New fee accrual is denominated in canonical vault shares and stored on",
11877
+ "`VaultAccounting`. This account remains in existing instruction schemas for",
11878
+ "compatibility; its historical accounting-unit counters are no longer updated."
11884
11879
  ],
11885
11880
  "serialization": "bytemuck",
11886
11881
  "repr": {
@@ -12105,8 +12100,9 @@ var IDL = {
12105
12100
  {
12106
12101
  "name": "migrate_amount",
12107
12102
  "docs": [
12108
- "Reserved for partial migration; partial migration is unsupported, so this",
12109
- "must be `None` (a full vault migration). A `Some(_)` value is rejected."
12103
+ "Partial migration remains unsupported. `None` performs a regular full",
12104
+ "vault migration; `Some(0)` explicitly marks the final in-scope vault and",
12105
+ "permits bounded terminal source-accounting reconciliation."
12110
12106
  ],
12111
12107
  "type": {
12112
12108
  "option": "u64"
@@ -13410,10 +13406,16 @@ var IDL = {
13410
13406
  }
13411
13407
  },
13412
13408
  {
13413
- "name": "_padding_bool",
13409
+ "name": "migration_in_progress",
13414
13410
  "docs": [
13415
- "Reserved padding (previously `apy_settle_skip`). Kept as a field to",
13416
- "preserve the on-chain account layout for already-deployed vaults."
13411
+ "True while a legacy migration destination is still receiving backing",
13412
+ "and receipt-supply accounting. Oracle mutation and NAV settlement stay",
13413
+ "disabled until every configured receipt mint authority has moved to this vault",
13414
+ "and migration finalization clears the flag.",
13415
+ "",
13416
+ "This occupies the former `apy_settle_skip` padding byte, preserving the",
13417
+ "on-chain account layout for already-deployed vaults. Existing vaults read",
13418
+ "it as false."
13417
13419
  ],
13418
13420
  "type": {
13419
13421
  "defined": {
@@ -13724,7 +13726,7 @@ var IDL = {
13724
13726
  {
13725
13727
  "name": "tvl_limit",
13726
13728
  "docs": [
13727
- "Maximum TVL in deposit-asset base units. `0` disables the cap."
13729
+ "Maximum TVL in vault accounting units. `0` disables the cap."
13728
13730
  ],
13729
13731
  "type": "u64"
13730
13732
  },
@@ -14784,7 +14786,7 @@ var IDL = {
14784
14786
  {
14785
14787
  "name": "total_mint_supply",
14786
14788
  "docs": [
14787
- "Total supply of the vault's share mint."
14789
+ "Effective share supply: physical mint supply plus unminted fee shares."
14788
14790
  ],
14789
14791
  "type": "u64"
14790
14792
  },
@@ -14838,12 +14840,26 @@ var IDL = {
14838
14840
  }
14839
14841
  }
14840
14842
  },
14843
+ {
14844
+ "name": "pending_curator_fee_shares",
14845
+ "docs": [
14846
+ "Vault shares owed to the curator but not yet minted."
14847
+ ],
14848
+ "type": "u64"
14849
+ },
14850
+ {
14851
+ "name": "pending_protocol_fee_shares",
14852
+ "docs": [
14853
+ "Vault shares owed to the protocol but not yet minted."
14854
+ ],
14855
+ "type": "u64"
14856
+ },
14841
14857
  {
14842
14858
  "name": "_padding1",
14843
14859
  "type": {
14844
14860
  "array": [
14845
14861
  "u64",
14846
- 32
14862
+ 30
14847
14863
  ]
14848
14864
  }
14849
14865
  },
@@ -14892,8 +14908,8 @@ var IDL = {
14892
14908
  {
14893
14909
  "name": "asset_decimals",
14894
14910
  "docs": [
14895
- "Decimals of the deposit asset, cached so deposit/withdraw paths don't",
14896
- "need to deserialize the mint account."
14911
+ "Vault accounting precision. This matches the vault share mint; each",
14912
+ "holding stores its own mint precision independently."
14897
14913
  ],
14898
14914
  "type": "u8"
14899
14915
  },
@@ -14925,7 +14941,7 @@ var IDL = {
14925
14941
  {
14926
14942
  "name": "tvl_limit",
14927
14943
  "docs": [
14928
- "Maximum TVL in deposit-asset base units. `0` disables the cap."
14944
+ "Maximum TVL in vault accounting units. `0` disables the cap."
14929
14945
  ],
14930
14946
  "type": "u64"
14931
14947
  },
@@ -15709,8 +15725,8 @@ function coerceBool(value) {
15709
15725
  if (value && typeof value.toBool === "function") {
15710
15726
  return value.toBool();
15711
15727
  }
15712
- const record = value;
15713
- return Boolean(record?.value ?? record?.[0]);
15728
+ const record2 = value;
15729
+ return Boolean(record2?.value ?? record2?.[0]);
15714
15730
  }
15715
15731
 
15716
15732
  // src/client/builders/base.ts
@@ -15746,8 +15762,8 @@ function coerceBool2(value) {
15746
15762
  if (value && typeof value.toBool === "function") {
15747
15763
  return value.toBool();
15748
15764
  }
15749
- const record = value;
15750
- return Boolean(record?.value ?? record?.[0]);
15765
+ const record2 = value;
15766
+ return Boolean(record2?.value ?? record2?.[0]);
15751
15767
  }
15752
15768
  function pubkeyToAddress(value) {
15753
15769
  if (typeof value === "string") return (0, import_kit5.address)(value);
@@ -15757,8 +15773,8 @@ function pubkeyToAddress(value) {
15757
15773
  return (0, import_kit5.address)(String(value));
15758
15774
  }
15759
15775
  function tokenProgramAddressFromIdlEnum(value) {
15760
- const record = value;
15761
- if (record && "token2022" in record) {
15776
+ const record2 = value;
15777
+ if (record2 && "token2022" in record2) {
15762
15778
  return TOKEN_PROGRAM_ID;
15763
15779
  }
15764
15780
  return (0, import_kit5.address)(import_spl_token2.TOKEN_PROGRAM_ID.toBase58());
@@ -16132,7 +16148,7 @@ var CreateVaultBuilder = class extends VaultBuilderBase {
16132
16148
  const [vault] = await this.pda.deriveVaultPda(vaultId);
16133
16149
  const [vaultOracle] = await this.pda.deriveVaultOraclePda(vault);
16134
16150
  const [feeVault] = await this.pda.deriveFeeAuthorityPda(vault);
16135
- const assetDecimals = (await (0, import_token.fetchMint)(this.rpc, txArgs.strictAssetMint)).data.decimals;
16151
+ const accountingDecimals = (await (0, import_token.fetchMint)(this.rpc, txArgs.shareMint)).data.decimals;
16136
16152
  return {
16137
16153
  curator: txArgs.curator,
16138
16154
  vault,
@@ -16157,7 +16173,7 @@ var CreateVaultBuilder = class extends VaultBuilderBase {
16157
16173
  initialMintSharePrice: null,
16158
16174
  basePriceOracleType: txArgs.basePriceOracleType ?? 1,
16159
16175
  basePrice: new import_core3.BN(
16160
- (txArgs.basePrice ?? 10n ** BigInt(assetDecimals)).toString()
16176
+ (txArgs.basePrice ?? 10n ** BigInt(accountingDecimals)).toString()
16161
16177
  ),
16162
16178
  basePriceOracleAccount: txArgs.basePriceOracleAccount ?? DEFAULT_PRICE_ORACLE_ACCOUNT,
16163
16179
  forMigration: txArgs.forMigration ?? false
@@ -16333,8 +16349,9 @@ var SetProtocolFeeBuilder = class extends VaultBuilderBase {
16333
16349
  const [derivedVaultOracle] = await this.pda.deriveVaultOraclePda(
16334
16350
  txArgs.vault
16335
16351
  );
16352
+ const defaultProtocolAuthority = this.program.programId.toBase58() === VAULT_PROGRAM_ID ? LOCAL_PROTOCOL_ADMIN : PROTOCOL_ADMIN;
16336
16353
  return {
16337
- protocolAuthority: txArgs.protocolAuthority ?? PROTOCOL_ADMIN,
16354
+ protocolAuthority: txArgs.protocolAuthority ?? defaultProtocolAuthority,
16338
16355
  vault: txArgs.vault,
16339
16356
  vaultOracle: txArgs.vaultOracle ?? derivedVaultOracle,
16340
16357
  args: {
@@ -16531,82 +16548,53 @@ var CrankPerformanceFeesBuilder = class extends VaultBuilderBase {
16531
16548
  return this.program.methods.crankPerformanceFees().accountsPartial({
16532
16549
  cranker: (0, import_common18.toWeb3Pk)(args.cranker),
16533
16550
  vault: (0, import_common18.toWeb3Pk)(args.vault),
16534
- feeAssetMint: (0, import_common18.toWeb3Pk)(args.feeAssetMint),
16535
- feeVault: (0, import_common18.toWeb3Pk)(args.feeVault),
16536
- feeVaultAta: (0, import_common18.toWeb3Pk)(args.feeVaultAta),
16551
+ shareMint: (0, import_common18.toWeb3Pk)(args.shareMint),
16537
16552
  feeCollector: (0, import_common18.toWeb3Pk)(args.feeCollector),
16538
- feeCollectorFeeAssetAta: (0, import_common18.toWeb3Pk)(args.feeCollectorFeeAssetAta),
16553
+ feeCollectorShareAta: (0, import_common18.toWeb3Pk)(args.feeCollectorShareAta),
16539
16554
  protocolFeeCollector: (0, import_common18.toWeb3Pk)(args.protocolFeeCollector),
16540
- protocolFeeCollectorFeeAssetAta: (0, import_common18.toWeb3Pk)(
16541
- args.protocolFeeCollectorFeeAssetAta
16555
+ protocolFeeCollectorShareAta: (0, import_common18.toWeb3Pk)(
16556
+ args.protocolFeeCollectorShareAta
16542
16557
  ),
16543
- feeAssetTokenProgram: (0, import_common18.toWeb3Pk)(args.feeAssetTokenProgram),
16558
+ shareTokenProgram: (0, import_common18.toWeb3Pk)(args.shareTokenProgram),
16544
16559
  associatedTokenProgram: import_spl_token6.ASSOCIATED_TOKEN_PROGRAM_ID,
16545
16560
  systemProgram: import_web38.SystemProgram.programId
16546
16561
  }).instruction().then(import_common18.toKitInstruction);
16547
16562
  }
16548
16563
  async deriveIxArgs(txArgs) {
16549
- const feeAssetMint = await resolveVaultBaseAssetMint(
16564
+ const vaultState = await this.account.fetchVault(txArgs.vault);
16565
+ const shareMint = (0, import_common18.fromWeb3Pk)(vaultState.mint);
16566
+ const shareTokenProgram = txArgs.shareTokenProgram ?? tokenProgramAddressFromIdlEnum(vaultState.mintTokenProgram);
16567
+ const feeCollector = await resolveVaultFeeCollector(
16550
16568
  this.account,
16551
16569
  txArgs.vault,
16552
- txArgs.feeAssetMint
16570
+ txArgs.feeCollector
16553
16571
  );
16554
- const [feeVault] = await this.pda.deriveFeeAuthorityPda(txArgs.vault);
16555
- const [feeCollector, feeAssetTokenProgram] = await Promise.all([
16556
- resolveVaultFeeCollector(this.account, txArgs.vault, txArgs.feeCollector),
16557
- resolveFeeAssetTokenProgram(
16558
- this.account,
16559
- txArgs.vault,
16560
- feeAssetMint,
16561
- txArgs.feeAssetTokenProgram
16562
- )
16563
- ]);
16564
16572
  const protocolFeeCollector = resolveProtocolFeeRecipient(
16565
16573
  txArgs.protocolFeeCollector
16566
16574
  );
16567
16575
  return {
16568
16576
  cranker: txArgs.cranker,
16569
16577
  vault: txArgs.vault,
16570
- feeAssetMint,
16571
- feeVault,
16572
- feeVaultAta: (0, import_common18.getAtaAddress)(
16573
- feeAssetMint,
16574
- feeVault,
16575
- feeAssetTokenProgram,
16576
- true
16577
- ),
16578
+ shareMint,
16578
16579
  feeCollector,
16579
- feeCollectorFeeAssetAta: (0, import_common18.getAtaAddress)(
16580
- feeAssetMint,
16580
+ feeCollectorShareAta: (0, import_common18.getAtaAddress)(
16581
+ shareMint,
16581
16582
  feeCollector,
16582
- feeAssetTokenProgram
16583
+ shareTokenProgram
16583
16584
  ),
16584
16585
  protocolFeeCollector,
16585
16586
  // The protocol fee recipient is a hardcoded protocol-controlled address
16586
16587
  // that may be off-curve (e.g. a PDA / multisig vault), so allow an
16587
16588
  // off-curve owner when deriving its ATA.
16588
- protocolFeeCollectorFeeAssetAta: (0, import_common18.getAtaAddress)(
16589
- feeAssetMint,
16589
+ protocolFeeCollectorShareAta: (0, import_common18.getAtaAddress)(
16590
+ shareMint,
16590
16591
  protocolFeeCollector,
16591
- feeAssetTokenProgram,
16592
+ shareTokenProgram,
16592
16593
  true
16593
16594
  ),
16594
- feeAssetTokenProgram
16595
+ shareTokenProgram
16595
16596
  };
16596
16597
  }
16597
- async buildPreambleInstructions(args) {
16598
- const payer = (0, import_common18.toWeb3Pk)(args.cranker);
16599
- return [
16600
- (0, import_spl_token6.createAssociatedTokenAccountIdempotentInstruction)(
16601
- payer,
16602
- (0, import_common18.toWeb3Pk)(args.feeVaultAta),
16603
- (0, import_common18.toWeb3Pk)(args.feeVault),
16604
- (0, import_common18.toWeb3Pk)(args.feeAssetMint),
16605
- (0, import_common18.toWeb3Pk)(args.feeAssetTokenProgram),
16606
- import_spl_token6.ASSOCIATED_TOKEN_PROGRAM_ID
16607
- )
16608
- ].map(import_common18.toKitInstruction);
16609
- }
16610
16598
  async buildPlanExtras(args) {
16611
16599
  return {
16612
16600
  postSuccessCacheInvalidations: [{ vaultPda: args.vault }]
@@ -16614,11 +16602,10 @@ var CrankPerformanceFeesBuilder = class extends VaultBuilderBase {
16614
16602
  }
16615
16603
  async getTx(txArgs) {
16616
16604
  const args = await this.deriveIxArgs(txArgs);
16617
- const preambleInstructions = await this.buildPreambleInstructions(args);
16618
16605
  const instruction = await this.getIx(args);
16619
16606
  const extras = await this.buildPlanExtras(args);
16620
16607
  return {
16621
- instructions: [...preambleInstructions, instruction],
16608
+ instructions: [instruction],
16622
16609
  ...extras ?? {}
16623
16610
  };
16624
16611
  }
@@ -19287,6 +19274,70 @@ var JupiterPriceSource = class {
19287
19274
  }
19288
19275
  };
19289
19276
 
19277
+ // src/services/consensusOracle/nestPriceSource.ts
19278
+ var import_kit12 = require("@solana/kit");
19279
+ var NEST_API_BASE_URL = "https://api.nest.credit/v1";
19280
+ var NEST_VAULT_SLUG = "nest-perena-vault";
19281
+ var NEST_RWA_SHARE_MINT = (0, import_kit12.address)(
19282
+ "VyXKJnVhkSkB6KAozSZCiLQbuB1k1r6Nu4etNYVo5LJ"
19283
+ );
19284
+ async function fetchNestTokenPrice(nestVaultSlug = NEST_VAULT_SLUG, opts = {}) {
19285
+ const baseUrl = (opts.baseUrl ?? NEST_API_BASE_URL).replace(/\/$/, "");
19286
+ const response = await (opts.fetchFn ?? fetch)(
19287
+ `${baseUrl}/vaults/${encodeURIComponent(nestVaultSlug)}/price`
19288
+ );
19289
+ if (!response.ok) {
19290
+ throw new Error(
19291
+ `Nest price API request failed: ${response.status} ${response.statusText}`
19292
+ );
19293
+ }
19294
+ const body = await response.json();
19295
+ const price = [body.data?.interpolatedPrice, body.data?.price].map(Number).find((candidate) => Number.isFinite(candidate) && candidate > 0);
19296
+ if (price === void 0) {
19297
+ throw new Error("Nest price API returned no positive share price");
19298
+ }
19299
+ return price;
19300
+ }
19301
+ var NestPriceSource = class {
19302
+ constructor(opts = {}) {
19303
+ this.shareMint = opts.shareMint ?? NEST_RWA_SHARE_MINT;
19304
+ this.nestVaultSlug = opts.nestVaultSlug ?? NEST_VAULT_SLUG;
19305
+ this.options = { baseUrl: opts.baseUrl, fetchFn: opts.fetchFn };
19306
+ }
19307
+ async fetchUsdPrices(mints) {
19308
+ if (!mints.some((mint) => mint.toString() === this.shareMint.toString())) {
19309
+ return {};
19310
+ }
19311
+ return {
19312
+ [this.shareMint.toString()]: await fetchNestTokenPrice(
19313
+ this.nestVaultSlug,
19314
+ this.options
19315
+ )
19316
+ };
19317
+ }
19318
+ };
19319
+
19320
+ // src/services/consensusOracle/livePriceSource.ts
19321
+ var LivePriceSource = class {
19322
+ constructor(opts = {}) {
19323
+ this.jupiter = opts.jupiter ?? new JupiterPriceSource();
19324
+ this.nest = opts.nest ?? new NestPriceSource();
19325
+ }
19326
+ async fetchUsdPrices(mints) {
19327
+ const unique = [
19328
+ ...new Map(mints.map((mint) => [mint.toString(), mint])).values()
19329
+ ];
19330
+ const nestMint = this.nest.shareMint.toString();
19331
+ const jupiterMints = unique.filter((mint) => mint.toString() !== nestMint);
19332
+ const nestMints = unique.filter((mint) => mint.toString() === nestMint);
19333
+ const [jupiterPrices, nestPrices] = await Promise.all([
19334
+ this.jupiter.fetchUsdPrices(jupiterMints),
19335
+ this.nest.fetchUsdPrices(nestMints)
19336
+ ]);
19337
+ return { ...jupiterPrices, ...nestPrices };
19338
+ }
19339
+ };
19340
+
19290
19341
  // src/services/consensusOracle/jupiterBalanceSource.ts
19291
19342
  var import_web323 = require("@solana/web3.js");
19292
19343
  var import_spl_token19 = require("@solana/spl-token");
@@ -19395,12 +19446,12 @@ var StaticPositionProvider = class {
19395
19446
  };
19396
19447
 
19397
19448
  // src/services/consensusOracle/kaminoPositionProvider.ts
19398
- var import_kit12 = require("@solana/kit");
19449
+ var import_kit13 = require("@solana/kit");
19399
19450
  var import_web324 = require("@solana/web3.js");
19400
19451
  var import_klend_sdk = require("@kamino-finance/klend-sdk");
19401
19452
  async function readKaminoBalance(manager, vault, sharesHolder) {
19402
19453
  const userShares = await manager.getUserSharesBalanceSingleVault(
19403
- (0, import_kit12.address)(sharesHolder.toBase58()),
19454
+ (0, import_kit13.address)(sharesHolder.toBase58()),
19404
19455
  vault
19405
19456
  );
19406
19457
  const tokensPerShare = await manager.getTokensPerShareSingleVault(vault);
@@ -19416,7 +19467,7 @@ var KaminoPositionProvider = class {
19416
19467
  async positionsFor(ctx) {
19417
19468
  const refs = ctx.refs.filter((r) => r.kind === "kamino");
19418
19469
  if (refs.length === 0) return [];
19419
- const rpc = (0, import_kit12.createSolanaRpc)(this.rpcUrl);
19470
+ const rpc = (0, import_kit13.createSolanaRpc)(this.rpcUrl);
19420
19471
  const slotDuration = await (0, import_klend_sdk.getMedianSlotDurationInMsFromLastEpochs)();
19421
19472
  const manager = new import_klend_sdk.KaminoManager(rpc, slotDuration);
19422
19473
  const out = [];
@@ -19429,7 +19480,7 @@ var KaminoPositionProvider = class {
19429
19480
  );
19430
19481
  continue;
19431
19482
  }
19432
- const kVault = new import_klend_sdk.KaminoVault(rpc, (0, import_kit12.address)(vaultState));
19483
+ const kVault = new import_klend_sdk.KaminoVault(rpc, (0, import_kit13.address)(vaultState));
19433
19484
  const amount = await readKaminoBalance(
19434
19485
  manager,
19435
19486
  kVault,
@@ -19548,7 +19599,7 @@ function createLiveConsensusOracleDeps(connection, opts = {}) {
19548
19599
  const log = opts.log ?? (() => {
19549
19600
  });
19550
19601
  const deps = {
19551
- priceSource: new JupiterPriceSource(),
19602
+ priceSource: new LivePriceSource(),
19552
19603
  balanceSource: new JupiterBalanceSource(connection, {
19553
19604
  rpcOnly: opts.rpcOnly ?? false,
19554
19605
  log
@@ -19571,8 +19622,861 @@ function createLiveConsensusOracleDeps(connection, opts = {}) {
19571
19622
  }
19572
19623
 
19573
19624
  // src/services/consensusOracle/consensusOracleService.ts
19574
- var import_web326 = require("@solana/web3.js");
19625
+ var import_web327 = require("@solana/web3.js");
19575
19626
  var import_common41 = __toESM(require_dist());
19627
+
19628
+ // src/services/consensusOracle/settlementSimulator.ts
19629
+ var import_kit14 = require("@solana/kit");
19630
+ var import_web326 = require("@solana/web3.js");
19631
+ var DEFAULT_SHARE_PRICE = 1000000n;
19632
+ var BPS_DENOMINATOR2 = 10000n;
19633
+ var SECONDS_PER_YEAR = 31536000n;
19634
+ var DEFAULT_STALENESS_SECS = 86400n;
19635
+ var CONSENSUS_MAX_DIFF_BPS = 8n;
19636
+ var MIN_CONSENSUS_SIGNERS = 2;
19637
+ var MAX_HOLDINGS = 12;
19638
+ var MAX_SIGNERS = 4;
19639
+ var ENTRY_SIZE = 272;
19640
+ var ENTRIES_OFFSET = 40;
19641
+ var PRICE_OFFSET = 40;
19642
+ var EXTERNAL_OFFSET = PRICE_OFFSET + MAX_HOLDINGS * 8;
19643
+ var APY_SCALE = 1000000000000000000n;
19644
+ var APY_LN_2 = 693147180559945309n;
19645
+ var APY_SERIES_TERMS = 32;
19646
+ function simulateConsensusOracleSettlement(args) {
19647
+ const warnings = [];
19648
+ const blockers = [];
19649
+ const vaultAccounting = record(args.vault.accounting);
19650
+ const feesConfig = record(args.vault.config.fees);
19651
+ const apyConfig = record(args.vault.config.apy);
19652
+ const tranchingEnabled = bool(args.vault.tranchingEnabled);
19653
+ const currentTvl = bigint(vaultAccounting.tvl);
19654
+ const pendingCuratorShares = bigint(vaultAccounting.pendingCuratorFeeShares);
19655
+ const pendingProtocolShares = bigint(
19656
+ vaultAccounting.pendingProtocolFeeShares
19657
+ );
19658
+ const cachedSupply = bigint(vaultAccounting.totalMintSupply);
19659
+ const reconciledSupply = args.physicalShareSupply === void 0 ? cachedSupply : args.physicalShareSupply + pendingCuratorShares + pendingProtocolShares;
19660
+ if (args.physicalShareSupply === void 0) {
19661
+ warnings.push(
19662
+ "regular share-mint supply was unavailable; using cached effective supply"
19663
+ );
19664
+ } else if (reconciledSupply !== cachedSupply) {
19665
+ warnings.push(
19666
+ `crank supply reconciliation changes regular supply ${cachedSupply} -> ${reconciledSupply}`
19667
+ );
19668
+ }
19669
+ const holdings = args.vault.holdings.map(decodeHolding);
19670
+ const oracle = decodeOracleData(args.oracleData, args.nowTs);
19671
+ const signerEntry = oracle.entries.find(
19672
+ (entry) => entry.signer === args.signer.toString()
19673
+ );
19674
+ if (!signerEntry) {
19675
+ blockers.push(`signer ${args.signer} is not registered in the oracle`);
19676
+ } else {
19677
+ signerEntry.lastUpdateTs = args.nowTs;
19678
+ for (const update of args.updates) {
19679
+ signerEntry.prices[update.holdingIndex] = update.price;
19680
+ signerEntry.externalAmounts[update.holdingIndex] = update.externalAmount;
19681
+ }
19682
+ }
19683
+ const consensus = applyConsensus(
19684
+ holdings,
19685
+ oracle.entries,
19686
+ args.nowTs,
19687
+ oracle.stalenessThresholdSecs
19688
+ );
19689
+ const proposedUpdatesLanded = args.updates.filter(
19690
+ (update) => consensus.find(
19691
+ (result) => result.holdingIndex === update.holdingIndex && result.wouldUpdateHolding
19692
+ )
19693
+ ).length;
19694
+ const consensusSummary = {
19695
+ allProposedUpdatesLand: proposedUpdatesLanded === args.updates.length && args.updates.length > 0,
19696
+ proposedUpdatesLanded,
19697
+ proposedUpdatesTotal: args.updates.length
19698
+ };
19699
+ const currentTranche = tranchingEnabled ? decodeTrancheState(args.trancheState, args, warnings, blockers) : void 0;
19700
+ const current = snapshot(
19701
+ currentTvl,
19702
+ reconciledSupply,
19703
+ bigint(vaultAccounting.mintSharePrice),
19704
+ currentTranche
19705
+ );
19706
+ let grossNav;
19707
+ try {
19708
+ grossNav = grossNavFromHoldings(
19709
+ holdings,
19710
+ args.nowTs,
19711
+ positiveOrDefault(
19712
+ bigint(args.vault.config.priceStalenessThresholdSecs),
19713
+ DEFAULT_STALENESS_SECS
19714
+ )
19715
+ );
19716
+ } catch (error) {
19717
+ blockers.push(message(error));
19718
+ }
19719
+ if (grossNav === void 0 || blockers.length > 0) {
19720
+ return {
19721
+ nowTs: args.nowTs,
19722
+ assetDecimals: args.vault.config.assetDecimals,
19723
+ ...consensusSummary,
19724
+ canSettle: false,
19725
+ blockers,
19726
+ warnings,
19727
+ consensus,
19728
+ grossNav,
19729
+ current
19730
+ };
19731
+ }
19732
+ try {
19733
+ const settlement = settleVault({
19734
+ grossNav,
19735
+ nowTs: args.nowTs,
19736
+ currentTvl,
19737
+ currentSharePrice: bigint(vaultAccounting.mintSharePrice),
19738
+ totalSupply: reconciledSupply,
19739
+ lossesEnabled: bool(args.vault.lossesEnabled),
19740
+ accountingLastUpdateTs: bigint(vaultAccounting.lastUpdateTs),
19741
+ priorSettledNavTs: oracle.settledNavTs,
19742
+ performanceFeeBps: number(feesConfig.performanceFeeBps),
19743
+ protocolFeeBps: number(feesConfig.protocolFeeBps),
19744
+ hwmSharePrice: bigint(vaultAccounting.hwmSharePrice),
19745
+ fixedApyBps: number(apyConfig.fixedApyBps),
19746
+ maxApyBps: number(apyConfig.maxApyBps),
19747
+ apyAnchorSharePrice: bigint(apyConfig.anchorSharePrice),
19748
+ apyAnchorTs: bigint(apyConfig.anchorTs),
19749
+ tranche: currentTranche
19750
+ });
19751
+ return {
19752
+ nowTs: args.nowTs,
19753
+ assetDecimals: args.vault.config.assetDecimals,
19754
+ ...consensusSummary,
19755
+ canSettle: true,
19756
+ blockers,
19757
+ warnings,
19758
+ consensus,
19759
+ grossNav,
19760
+ settledAccountingNav: settlement.settledAccountingNav,
19761
+ current,
19762
+ projected: settlement.projected,
19763
+ performanceFees: settlement.performanceFees
19764
+ };
19765
+ } catch (error) {
19766
+ blockers.push(message(error));
19767
+ return {
19768
+ nowTs: args.nowTs,
19769
+ assetDecimals: args.vault.config.assetDecimals,
19770
+ ...consensusSummary,
19771
+ canSettle: false,
19772
+ blockers,
19773
+ warnings,
19774
+ consensus,
19775
+ grossNav,
19776
+ current
19777
+ };
19778
+ }
19779
+ }
19780
+ function applyConsensus(holdings, entries, nowTs, stalenessThresholdSecs) {
19781
+ const results = [];
19782
+ for (let index = 0; index < holdings.length; index += 1) {
19783
+ const holding = holdings[index];
19784
+ if (holding.cleared || holding.priceOracleType !== "consensusoracle") {
19785
+ continue;
19786
+ }
19787
+ const reports = entries.filter(
19788
+ (entry) => entry.signer !== import_web326.PublicKey.default.toBase58() && isFresh(entry.lastUpdateTs, nowTs, stalenessThresholdSecs) && (entry.prices[index] ?? 0n) > 0n
19789
+ );
19790
+ const prices = reports.map((entry) => entry.prices[index] ?? 0n);
19791
+ const amounts = reports.map((entry) => entry.externalAmounts[index] ?? 0n);
19792
+ let reason;
19793
+ if (reports.length < MIN_CONSENSUS_SIGNERS) {
19794
+ reason = `only ${reports.length} fresh priced report(s); need ${MIN_CONSENSUS_SIGNERS}`;
19795
+ } else if (!withinDeviation(prices)) {
19796
+ reason = `price reports exceed ${CONSENSUS_MAX_DIFF_BPS}bps pairwise deviation`;
19797
+ } else if (!withinDeviation(amounts)) {
19798
+ reason = `external-amount reports exceed ${CONSENSUS_MAX_DIFF_BPS}bps pairwise deviation`;
19799
+ }
19800
+ if (reason) {
19801
+ results.push({
19802
+ holdingIndex: index,
19803
+ mint: holding.mint,
19804
+ reportCount: reports.length,
19805
+ wouldUpdateHolding: false,
19806
+ reason
19807
+ });
19808
+ continue;
19809
+ }
19810
+ const settledPrice = average(prices);
19811
+ const settledExternalAmount = average(amounts);
19812
+ const latestTs = reports.reduce(
19813
+ (latest, entry) => entry.lastUpdateTs > latest ? entry.lastUpdateTs : latest,
19814
+ 0n
19815
+ );
19816
+ const wouldUpdateHolding = latestTs > holding.lastUpdateTs && latestTs <= nowTs;
19817
+ if (wouldUpdateHolding) {
19818
+ holding.price = settledPrice;
19819
+ holding.externalAmount = settledExternalAmount;
19820
+ holding.lastUpdateTs = latestTs;
19821
+ if (!holding.isBase && holding.localAmount === 0n && holding.externalAmount === 0n) {
19822
+ holding.cleared = true;
19823
+ }
19824
+ }
19825
+ results.push({
19826
+ holdingIndex: index,
19827
+ mint: holding.mint,
19828
+ reportCount: reports.length,
19829
+ settledPrice,
19830
+ settledExternalAmount,
19831
+ wouldUpdateHolding,
19832
+ reason: wouldUpdateHolding ? void 0 : `aggregate timestamp ${latestTs} is not newer than holding timestamp ${holding.lastUpdateTs}`
19833
+ });
19834
+ }
19835
+ return results;
19836
+ }
19837
+ function settleVault(args) {
19838
+ if (args.grossNav < args.currentTvl && !args.lossesEnabled) {
19839
+ throw new Error(
19840
+ `crank would fail LossesDisabled: gross NAV ${args.grossNav} < current TVL ${args.currentTvl}`
19841
+ );
19842
+ }
19843
+ const priorTs = args.priorSettledNavTs > 0n ? args.priorSettledNavTs : max(args.accountingLastUpdateTs, args.apyAnchorTs);
19844
+ const nextApyValue = args.tranche ? args.grossNav : sharePriceForValue(args.grossNav, args.totalSupply);
19845
+ if (nextApyValue !== void 0) {
19846
+ validateRealizedApy(
19847
+ args.tranche ? args.currentTvl : args.currentSharePrice,
19848
+ priorTs,
19849
+ nextApyValue,
19850
+ args.nowTs,
19851
+ args.maxApyBps
19852
+ );
19853
+ }
19854
+ let regularValue;
19855
+ let regularSharePrice = args.currentSharePrice;
19856
+ let curatorFee = 0n;
19857
+ let protocolFee = 0n;
19858
+ let settledAccountingNav;
19859
+ if (args.tranche) {
19860
+ settledAccountingNav = args.grossNav;
19861
+ regularValue = settleTrancheNav(
19862
+ args.tranche,
19863
+ args.currentTvl,
19864
+ settledAccountingNav,
19865
+ args.nowTs
19866
+ );
19867
+ const juniorFees = settleShareClassPerformanceFee(
19868
+ args.tranche.junior,
19869
+ args.performanceFeeBps,
19870
+ args.protocolFeeBps
19871
+ );
19872
+ const regularFees = settleRegularPerformanceFee(
19873
+ regularValue,
19874
+ args.totalSupply,
19875
+ args.hwmSharePrice,
19876
+ args.performanceFeeBps,
19877
+ args.protocolFeeBps
19878
+ );
19879
+ regularValue = regularFees.netValue;
19880
+ regularSharePrice = sharePriceForValue(regularValue, args.totalSupply) ?? regularSharePrice;
19881
+ curatorFee = juniorFees.curator + regularFees.fees.curator;
19882
+ protocolFee = juniorFees.protocol + regularFees.fees.protocol;
19883
+ } else {
19884
+ settledAccountingNav = settleFixedApyNav({
19885
+ currentSharePrice: args.currentSharePrice,
19886
+ reportedNav: args.grossNav,
19887
+ nowTs: args.nowTs,
19888
+ totalSupply: args.totalSupply,
19889
+ fixedApyBps: args.fixedApyBps,
19890
+ anchorSharePrice: args.apyAnchorSharePrice,
19891
+ anchorTs: args.apyAnchorTs
19892
+ });
19893
+ const regularFees = settleRegularPerformanceFee(
19894
+ settledAccountingNav,
19895
+ args.totalSupply,
19896
+ args.hwmSharePrice,
19897
+ args.performanceFeeBps,
19898
+ args.protocolFeeBps
19899
+ );
19900
+ regularValue = regularFees.netValue;
19901
+ regularSharePrice = sharePriceForValue(regularValue, args.totalSupply) ?? regularSharePrice;
19902
+ curatorFee = regularFees.fees.curator;
19903
+ protocolFee = regularFees.fees.protocol;
19904
+ }
19905
+ const totalFees = curatorFee + protocolFee;
19906
+ const netRegularBacking = mulDiv2(
19907
+ args.totalSupply,
19908
+ regularSharePrice,
19909
+ DEFAULT_SHARE_PRICE
19910
+ );
19911
+ let mintedShares = 0n;
19912
+ if (totalFees > 0n) {
19913
+ mintedShares = args.totalSupply === 0n ? totalFees : mulDiv2(totalFees, args.totalSupply, netRegularBacking);
19914
+ if (mintedShares === 0n) {
19915
+ throw new Error(
19916
+ "crank would fail ZeroAssetAmount while accruing fee shares"
19917
+ );
19918
+ }
19919
+ }
19920
+ const projectedSupply = args.totalSupply + mintedShares;
19921
+ const projected = snapshot(
19922
+ // Fee value is carved out, then added back when converted to vault shares.
19923
+ settledAccountingNav,
19924
+ projectedSupply,
19925
+ regularSharePrice,
19926
+ args.tranche
19927
+ );
19928
+ return {
19929
+ settledAccountingNav,
19930
+ projected,
19931
+ performanceFees: {
19932
+ curator: curatorFee,
19933
+ protocol: protocolFee,
19934
+ total: totalFees,
19935
+ mintedShares
19936
+ }
19937
+ };
19938
+ }
19939
+ function settleTrancheNav(tranche, currentTvl, nextTvl, nowTs) {
19940
+ const before = tranche.junior.value + tranche.senior.value;
19941
+ if (before === 0n) {
19942
+ tranche.lastSettledTs = nowTs;
19943
+ return nextTvl;
19944
+ }
19945
+ if (currentTvl <= 0n || before > currentTvl) {
19946
+ throw new Error(
19947
+ `crank would fail InvalidArgument: tranche value ${before}, current TVL ${currentTvl}`
19948
+ );
19949
+ }
19950
+ const after = mulDiv2(before, nextTvl, currentTvl);
19951
+ if (after >= before) {
19952
+ let gain = after - before;
19953
+ const entitlement = seniorEntitlement(tranche, nowTs);
19954
+ const seniorGain = entitlement < gain ? entitlement : gain;
19955
+ tranche.senior.value += seniorGain;
19956
+ gain -= seniorGain;
19957
+ if (gain > 0n) {
19958
+ if (tranche.junior.totalSupply > 0n) tranche.junior.value += gain;
19959
+ else tranche.senior.value += gain;
19960
+ }
19961
+ } else {
19962
+ const loss = before - after;
19963
+ const juniorLoss = tranche.junior.value < loss ? tranche.junior.value : loss;
19964
+ tranche.junior.value -= juniorLoss;
19965
+ tranche.senior.value -= loss - juniorLoss;
19966
+ }
19967
+ refreshShareClass(tranche.junior);
19968
+ refreshShareClass(tranche.senior);
19969
+ tranche.lastSettledTs = nowTs;
19970
+ return nextTvl - tranche.junior.value - tranche.senior.value;
19971
+ }
19972
+ function seniorEntitlement(tranche, nowTs) {
19973
+ if (tranche.seniorApyAnchorTs <= 0n) {
19974
+ tranche.seniorApyAnchorSharePrice = tranche.senior.sharePrice;
19975
+ tranche.seniorApyAnchorTs = tranche.lastSettledTs > 0n ? tranche.lastSettledTs : nowTs;
19976
+ }
19977
+ if (tranche.seniorFixedApyBps === 0 || tranche.seniorApyAnchorSharePrice === 0n || tranche.senior.totalSupply === 0n || tranche.seniorApyAnchorTs <= 0n || nowTs <= tranche.seniorApyAnchorTs) {
19978
+ return 0n;
19979
+ }
19980
+ const targetPrice = applyEffectiveApy(
19981
+ tranche.seniorApyAnchorSharePrice,
19982
+ tranche.seniorFixedApyBps,
19983
+ nowTs - tranche.seniorApyAnchorTs
19984
+ );
19985
+ const targetValue = mulDiv2(
19986
+ targetPrice,
19987
+ tranche.senior.totalSupply,
19988
+ DEFAULT_SHARE_PRICE
19989
+ );
19990
+ return targetValue > tranche.senior.value ? targetValue - tranche.senior.value : 0n;
19991
+ }
19992
+ function settleShareClassPerformanceFee(shareClass, performanceFeeBps, protocolFeeBps) {
19993
+ refreshShareClass(shareClass);
19994
+ const grossPrice = shareClass.sharePrice;
19995
+ if (shareClass.hwmSharePrice === 0n) {
19996
+ shareClass.hwmSharePrice = grossPrice;
19997
+ return noFees();
19998
+ }
19999
+ if (performanceFeeBps + protocolFeeBps === 0 || shareClass.totalSupply === 0n || grossPrice <= shareClass.hwmSharePrice) {
20000
+ return noFees();
20001
+ }
20002
+ const gainValue = mulDiv2(
20003
+ grossPrice - shareClass.hwmSharePrice,
20004
+ shareClass.totalSupply,
20005
+ DEFAULT_SHARE_PRICE
20006
+ );
20007
+ const fees = feeAmounts(gainValue, performanceFeeBps, protocolFeeBps);
20008
+ const total = fees.curator + fees.protocol;
20009
+ if (total > 0n) {
20010
+ shareClass.value -= total;
20011
+ refreshShareClass(shareClass);
20012
+ shareClass.hwmSharePrice = shareClass.sharePrice;
20013
+ }
20014
+ return fees;
20015
+ }
20016
+ function settleRegularPerformanceFee(grossValue, supply, hwmSharePrice, performanceFeeBps, protocolFeeBps) {
20017
+ if (supply === 0n) return { netValue: grossValue, fees: noFees() };
20018
+ const grossPrice = sharePriceForValue(grossValue, supply);
20019
+ if (hwmSharePrice === 0n || grossPrice <= hwmSharePrice || performanceFeeBps + protocolFeeBps === 0) {
20020
+ return { netValue: grossValue, fees: noFees() };
20021
+ }
20022
+ const gainValue = mulDiv2(
20023
+ supply,
20024
+ grossPrice - hwmSharePrice,
20025
+ DEFAULT_SHARE_PRICE
20026
+ );
20027
+ const fees = feeAmounts(gainValue, performanceFeeBps, protocolFeeBps);
20028
+ return {
20029
+ netValue: grossValue - fees.curator - fees.protocol,
20030
+ fees
20031
+ };
20032
+ }
20033
+ function settleFixedApyNav(args) {
20034
+ if (args.fixedApyBps === 0 || args.currentSharePrice === 0n || args.totalSupply === 0n || args.anchorSharePrice === 0n || args.anchorTs <= 0n) {
20035
+ return args.reportedNav;
20036
+ }
20037
+ if (args.nowTs <= args.anchorTs) {
20038
+ const anchoredNav = mulDiv2(
20039
+ args.totalSupply,
20040
+ args.anchorSharePrice,
20041
+ DEFAULT_SHARE_PRICE
20042
+ );
20043
+ if (args.reportedNav !== anchoredNav) {
20044
+ throw new Error("crank would fail InvalidOracleUpdate at APY anchor");
20045
+ }
20046
+ return args.reportedNav;
20047
+ }
20048
+ const fixedPrice = applyEffectiveApy(
20049
+ args.anchorSharePrice,
20050
+ args.fixedApyBps,
20051
+ args.nowTs - args.anchorTs
20052
+ );
20053
+ const fixedNav = mulDiv2(args.totalSupply, fixedPrice, DEFAULT_SHARE_PRICE);
20054
+ return args.reportedNav >= fixedNav ? fixedNav : args.reportedNav;
20055
+ }
20056
+ function validateRealizedApy(priorValue, priorTs, nextValue, nextTs, maxApyBps) {
20057
+ if (maxApyBps === 0 || priorValue === 0n || priorTs <= 0n || nextValue <= priorValue) {
20058
+ return;
20059
+ }
20060
+ const elapsed = nextTs - priorTs;
20061
+ if (elapsed <= 0n) throw new Error("crank would fail MaxApyExceeded");
20062
+ const lhs = (nextValue - priorValue) * BPS_DENOMINATOR2 * SECONDS_PER_YEAR;
20063
+ const rhs = BigInt(maxApyBps) * priorValue * elapsed;
20064
+ if (lhs > rhs) {
20065
+ const implied = lhs / (priorValue * elapsed);
20066
+ throw new Error(
20067
+ `crank would fail MaxApyExceeded: implied ${implied}bps > ${maxApyBps}bps`
20068
+ );
20069
+ }
20070
+ }
20071
+ function grossNavFromHoldings(holdings, nowTs, stalenessSecs) {
20072
+ let nav = 0n;
20073
+ for (const holding of holdings) {
20074
+ if (holding.cleared) continue;
20075
+ const amount = holding.localAmount + holding.externalAmount;
20076
+ if (amount === 0n && !holding.isBase) continue;
20077
+ if (holding.price <= 0n) {
20078
+ throw new Error(`crank blocked: holding ${holding.mint} is unpriced`);
20079
+ }
20080
+ if (holding.priceOracleType !== "none" && (holding.lastUpdateTs <= 0n || nowTs - holding.lastUpdateTs < 0n || nowTs - holding.lastUpdateTs > stalenessSecs)) {
20081
+ throw new Error(
20082
+ `crank blocked: holding ${holding.mint} price is stale (ts=${holding.lastUpdateTs})`
20083
+ );
20084
+ }
20085
+ if (amount > 0n) {
20086
+ nav += mulDiv2(amount, holding.price, 10n ** BigInt(holding.decimals));
20087
+ }
20088
+ }
20089
+ return nav;
20090
+ }
20091
+ function decodeOracleData(data, nowTs) {
20092
+ if (data.length < ENTRIES_OFFSET + MAX_SIGNERS * ENTRY_SIZE) {
20093
+ throw new Error(`oracle payload is too short (${data.length} bytes)`);
20094
+ }
20095
+ const entries = [];
20096
+ for (let signerIndex = 0; signerIndex < MAX_SIGNERS; signerIndex += 1) {
20097
+ const offset = ENTRIES_OFFSET + signerIndex * ENTRY_SIZE;
20098
+ const signerBytes = new Uint8Array(data.slice(offset, offset + 32));
20099
+ const prices = Array.from(
20100
+ { length: MAX_HOLDINGS },
20101
+ (_, holdingIndex) => readU64(data, offset + PRICE_OFFSET + holdingIndex * 8)
20102
+ );
20103
+ const externalAmounts = Array.from(
20104
+ { length: MAX_HOLDINGS },
20105
+ (_, holdingIndex) => readU64(data, offset + EXTERNAL_OFFSET + holdingIndex * 8)
20106
+ );
20107
+ entries.push({
20108
+ signer: new import_web326.PublicKey(signerBytes).toBase58(),
20109
+ lastUpdateTs: readI64(data, offset + 32),
20110
+ prices,
20111
+ externalAmounts
20112
+ });
20113
+ }
20114
+ const pendingOffset = ENTRIES_OFFSET + MAX_SIGNERS * ENTRY_SIZE;
20115
+ const pendingEffectiveTs = readI64(data, pendingOffset + 128);
20116
+ const pendingCount = data[pendingOffset + 136] ?? 0;
20117
+ if (pendingCount > 0 && pendingCount <= MAX_SIGNERS && nowTs >= pendingEffectiveTs) {
20118
+ for (let index = 0; index < MAX_SIGNERS; index += 1) {
20119
+ const signerBytes = new Uint8Array(
20120
+ data.slice(pendingOffset + index * 32, pendingOffset + (index + 1) * 32)
20121
+ );
20122
+ entries[index] = {
20123
+ signer: index < pendingCount ? new import_web326.PublicKey(signerBytes).toBase58() : import_web326.PublicKey.default.toBase58(),
20124
+ lastUpdateTs: 0n,
20125
+ prices: Array(MAX_HOLDINGS).fill(0n),
20126
+ externalAmounts: Array(MAX_HOLDINGS).fill(0n)
20127
+ };
20128
+ }
20129
+ }
20130
+ return {
20131
+ settledNavTs: readI64(data, 8),
20132
+ stalenessThresholdSecs: positiveOrDefault(
20133
+ readI64(data, 32),
20134
+ DEFAULT_STALENESS_SECS
20135
+ ),
20136
+ entries
20137
+ };
20138
+ }
20139
+ function decodeHolding(value) {
20140
+ const holding = record(value);
20141
+ const mintString = pubkeyString3(holding.mint);
20142
+ return {
20143
+ mint: (0, import_kit14.address)(mintString),
20144
+ decimals: number(holding.decimals),
20145
+ priceOracleType: variant(holding.priceOracleType),
20146
+ isBase: bool(holding.isBase),
20147
+ localAmount: bigint(holding.localAmount),
20148
+ externalAmount: bigint(holding.externalAmount),
20149
+ price: bigint(holding.price),
20150
+ lastUpdateTs: bigint(holding.lastUpdateTs),
20151
+ cleared: mintString === import_web326.PublicKey.default.toBase58()
20152
+ };
20153
+ }
20154
+ function decodeTrancheState(decoded, args, warnings, blockers) {
20155
+ if (!decoded) {
20156
+ blockers.push("tranching is enabled but the tranche state was unavailable");
20157
+ return void 0;
20158
+ }
20159
+ const junior = decodeShareClass(decoded.junior);
20160
+ const senior = decodeShareClass(decoded.senior);
20161
+ if (args.physicalJuniorSupply === void 0) {
20162
+ warnings.push(
20163
+ "junior mint supply unavailable; using cached tranche supply"
20164
+ );
20165
+ } else {
20166
+ junior.totalSupply = args.physicalJuniorSupply;
20167
+ refreshShareClass(junior);
20168
+ }
20169
+ if (args.physicalSeniorSupply === void 0) {
20170
+ warnings.push(
20171
+ "senior mint supply unavailable; using cached tranche supply"
20172
+ );
20173
+ } else {
20174
+ senior.totalSupply = args.physicalSeniorSupply;
20175
+ refreshShareClass(senior);
20176
+ }
20177
+ return {
20178
+ junior,
20179
+ senior,
20180
+ seniorFixedApyBps: number(decoded.config.seniorFixedApyBps),
20181
+ lastSettledTs: bigint(decoded.lastSettledTs),
20182
+ seniorApyAnchorSharePrice: bigint(decoded.seniorApyAnchorSharePrice),
20183
+ seniorApyAnchorTs: bigint(decoded.seniorApyAnchorTs)
20184
+ };
20185
+ }
20186
+ function decodeShareClass(value) {
20187
+ const decoded = record(value);
20188
+ return {
20189
+ value: bigint(decoded.value),
20190
+ totalSupply: bigint(decoded.totalSupply),
20191
+ sharePrice: bigint(decoded.sharePrice),
20192
+ hwmSharePrice: bigint(decoded.hwmSharePrice)
20193
+ };
20194
+ }
20195
+ function snapshot(tvl, regularSupply, regularSharePrice, tranche) {
20196
+ const regularValue = mulDiv2(
20197
+ regularSupply,
20198
+ regularSharePrice,
20199
+ DEFAULT_SHARE_PRICE
20200
+ );
20201
+ return {
20202
+ tvl,
20203
+ regular: {
20204
+ value: regularValue,
20205
+ totalSupply: regularSupply,
20206
+ sharePrice: regularSharePrice
20207
+ },
20208
+ ...tranche ? {
20209
+ junior: publicShareClass(tranche.junior),
20210
+ senior: publicShareClass(tranche.senior)
20211
+ } : {}
20212
+ };
20213
+ }
20214
+ function publicShareClass(value) {
20215
+ return {
20216
+ value: value.value,
20217
+ totalSupply: value.totalSupply,
20218
+ sharePrice: value.sharePrice
20219
+ };
20220
+ }
20221
+ function refreshShareClass(value) {
20222
+ value.sharePrice = value.totalSupply === 0n ? DEFAULT_SHARE_PRICE : mulDiv2(value.value, DEFAULT_SHARE_PRICE, value.totalSupply);
20223
+ }
20224
+ function sharePriceForValue(value, supply) {
20225
+ return supply === 0n ? void 0 : mulDiv2(value, DEFAULT_SHARE_PRICE, supply);
20226
+ }
20227
+ function feeAmounts(value, performanceFeeBps, protocolFeeBps) {
20228
+ return {
20229
+ curator: mulDiv2(value, BigInt(performanceFeeBps), BPS_DENOMINATOR2),
20230
+ protocol: mulDiv2(value, BigInt(protocolFeeBps), BPS_DENOMINATOR2)
20231
+ };
20232
+ }
20233
+ function noFees() {
20234
+ return { curator: 0n, protocol: 0n };
20235
+ }
20236
+ function withinDeviation(values) {
20237
+ for (let i = 0; i < values.length; i += 1) {
20238
+ for (let j = i + 1; j < values.length; j += 1) {
20239
+ const a = values[i];
20240
+ const b = values[j];
20241
+ if (a === b) continue;
20242
+ if (a === 0n || b === 0n) return false;
20243
+ const diff = abs(a * BPS_DENOMINATOR2 / b - BPS_DENOMINATOR2);
20244
+ if (diff > CONSENSUS_MAX_DIFF_BPS) return false;
20245
+ }
20246
+ }
20247
+ return true;
20248
+ }
20249
+ function average(values) {
20250
+ return values.reduce((sum, value) => sum + value, 0n) / BigInt(values.length);
20251
+ }
20252
+ function isFresh(lastTs, nowTs, staleness) {
20253
+ if (lastTs <= 0n) return false;
20254
+ const age = nowTs - lastTs;
20255
+ return age >= 0n && age <= staleness;
20256
+ }
20257
+ function applyEffectiveApy(anchor, apyBps, elapsedSecs) {
20258
+ if (anchor === 0n || apyBps === 0 || elapsedSecs === 0n) return anchor;
20259
+ if (apyBps < 0 || apyBps > 1e4) throw new Error("invalid APY bps");
20260
+ const base = APY_SCALE + mulDiv2(BigInt(apyBps), APY_SCALE, BPS_DENOMINATOR2);
20261
+ const wholeYears = elapsedSecs / SECONDS_PER_YEAR;
20262
+ const remainder = elapsedSecs % SECONDS_PER_YEAR;
20263
+ const wholeMultiplier = fixedPointPow(base, wholeYears);
20264
+ const fractionalMultiplier = remainder === 0n ? APY_SCALE : fixedPointExp(
20265
+ mulDiv2(
20266
+ fixedPointLnBetweenOneAndTwo(base),
20267
+ remainder,
20268
+ SECONDS_PER_YEAR
20269
+ )
20270
+ );
20271
+ return mulDiv2(
20272
+ anchor,
20273
+ fixedPointMul(wholeMultiplier, fractionalMultiplier),
20274
+ APY_SCALE
20275
+ );
20276
+ }
20277
+ function fixedPointMul(lhs, rhs) {
20278
+ const lhsWhole = lhs / APY_SCALE;
20279
+ const lhsRemainder = lhs % APY_SCALE;
20280
+ const rhsWhole = rhs / APY_SCALE;
20281
+ const rhsRemainder = rhs % APY_SCALE;
20282
+ return lhsWhole * rhs + lhsRemainder * rhsWhole + lhsRemainder * rhsRemainder / APY_SCALE;
20283
+ }
20284
+ function fixedPointPow(baseInput, exponentInput) {
20285
+ let base = baseInput;
20286
+ let exponent = exponentInput;
20287
+ let result = APY_SCALE;
20288
+ while (exponent > 0n) {
20289
+ if ((exponent & 1n) === 1n) result = fixedPointMul(result, base);
20290
+ exponent >>= 1n;
20291
+ if (exponent > 0n) base = fixedPointMul(base, base);
20292
+ }
20293
+ return result;
20294
+ }
20295
+ function fixedPointLnBetweenOneAndTwo(value) {
20296
+ if (value < APY_SCALE || value > 2n * APY_SCALE) {
20297
+ throw new Error("APY logarithm input out of range");
20298
+ }
20299
+ const z = mulDiv2(value - APY_SCALE, APY_SCALE, value + APY_SCALE);
20300
+ const zSquared = fixedPointMul(z, z);
20301
+ let power = z;
20302
+ let sum = 0n;
20303
+ for (let index = 0; index < APY_SERIES_TERMS; index += 1) {
20304
+ sum += power / BigInt(2 * index + 1);
20305
+ power = fixedPointMul(power, zSquared);
20306
+ }
20307
+ return sum * 2n;
20308
+ }
20309
+ function fixedPointExp(value) {
20310
+ if (value > APY_LN_2) throw new Error("APY exponent input out of range");
20311
+ let sum = APY_SCALE;
20312
+ let term = APY_SCALE;
20313
+ for (let divisor = 1; divisor <= APY_SERIES_TERMS; divisor += 1) {
20314
+ term = fixedPointMul(term, value) / BigInt(divisor);
20315
+ if (term === 0n) break;
20316
+ sum += term;
20317
+ }
20318
+ return sum;
20319
+ }
20320
+ function readU64(data, offset) {
20321
+ let value = 0n;
20322
+ for (let index = 0; index < 8; index += 1) {
20323
+ value |= BigInt(data[offset + index] ?? 0) << BigInt(index * 8);
20324
+ }
20325
+ return value;
20326
+ }
20327
+ function readI64(data, offset) {
20328
+ const value = readU64(data, offset);
20329
+ return value >= 0x8000000000000000n ? value - 0x10000000000000000n : value;
20330
+ }
20331
+ function mulDiv2(a, b, c) {
20332
+ if (c === 0n) throw new Error("division by zero in settlement simulation");
20333
+ return a * b / c;
20334
+ }
20335
+ function record(value) {
20336
+ return value && typeof value === "object" ? value : {};
20337
+ }
20338
+ function bigint(value) {
20339
+ if (value === void 0 || value === null) return 0n;
20340
+ if (typeof value === "bigint") return value;
20341
+ if (typeof value === "number" || typeof value === "string") {
20342
+ return BigInt(value);
20343
+ }
20344
+ return BigInt(String(value));
20345
+ }
20346
+ function number(value) {
20347
+ return Number(bigint(value));
20348
+ }
20349
+ function bool(value) {
20350
+ if (typeof value === "boolean") return value;
20351
+ if (typeof value === "number") return value !== 0;
20352
+ if (value && typeof value.toBool === "function") {
20353
+ return value.toBool();
20354
+ }
20355
+ const pod = value;
20356
+ return Boolean(pod?.value ?? pod?.[0]);
20357
+ }
20358
+ function variant(value) {
20359
+ return (value && typeof value === "object" ? Object.keys(value)[0] ?? "" : String(value ?? "")).toLowerCase();
20360
+ }
20361
+ function pubkeyString3(value) {
20362
+ if (typeof value === "string") return value;
20363
+ if (value && typeof value.toBase58 === "function") {
20364
+ return value.toBase58();
20365
+ }
20366
+ return String(value);
20367
+ }
20368
+ function positiveOrDefault(value, fallback) {
20369
+ return value > 0n ? value : fallback;
20370
+ }
20371
+ function max(a, b) {
20372
+ return a > b ? a : b;
20373
+ }
20374
+ function abs(value) {
20375
+ return value < 0n ? -value : value;
20376
+ }
20377
+ function message(error) {
20378
+ return error instanceof Error ? error.message : String(error);
20379
+ }
20380
+ function formatSettlementSimulation(simulation) {
20381
+ const lines = [];
20382
+ lines.push(
20383
+ ` proposed oracle values: ${simulation.allProposedUpdatesLand ? "WOULD REACH CONSENSUS" : "WOULD NOT ALL LAND"} (${simulation.proposedUpdatesLanded}/${simulation.proposedUpdatesTotal} holdings)`
20384
+ );
20385
+ lines.push(
20386
+ ` crank simulation: ${simulation.canSettle ? "WOULD SETTLE" : "BLOCKED"}`
20387
+ );
20388
+ for (const holding of simulation.consensus) {
20389
+ const detail = holding.settledPrice ? `price=${holding.settledPrice} external=${holding.settledExternalAmount}` : holding.reason ?? "no aggregate";
20390
+ lines.push(
20391
+ ` consensus #${holding.holdingIndex} ${holding.mint}: ${holding.reportCount} report(s), ${holding.wouldUpdateHolding ? "lands" : "unchanged"} (${detail})`
20392
+ );
20393
+ }
20394
+ if (simulation.grossNav !== void 0) {
20395
+ lines.push(
20396
+ ` gross NAV: ${formatUnits(
20397
+ simulation.grossNav,
20398
+ simulation.assetDecimals
20399
+ )} [${simulation.grossNav}]`
20400
+ );
20401
+ }
20402
+ if (simulation.settledAccountingNav !== void 0 && simulation.settledAccountingNav !== simulation.grossNav) {
20403
+ lines.push(
20404
+ ` accounting NAV after fixed APY: ${formatUnits(
20405
+ simulation.settledAccountingNav,
20406
+ simulation.assetDecimals
20407
+ )} [${simulation.settledAccountingNav}]`
20408
+ );
20409
+ }
20410
+ if (simulation.projected) {
20411
+ lines.push(
20412
+ ` TVL: ${formatTransition(
20413
+ simulation.current.tvl,
20414
+ simulation.projected.tvl,
20415
+ simulation.assetDecimals
20416
+ )}`
20417
+ );
20418
+ lines.push(
20419
+ ` regular: ${formatTransition(
20420
+ simulation.current.regular.sharePrice,
20421
+ simulation.projected.regular.sharePrice,
20422
+ 6
20423
+ )} per share`
20424
+ );
20425
+ lines.push(
20426
+ ` supply ${simulation.current.regular.totalSupply} -> ${simulation.projected.regular.totalSupply}, backing ${simulation.current.regular.value} -> ${simulation.projected.regular.value}`
20427
+ );
20428
+ if (simulation.current.junior && simulation.projected.junior) {
20429
+ lines.push(
20430
+ ` junior: ${formatTransition(
20431
+ simulation.current.junior.sharePrice,
20432
+ simulation.projected.junior.sharePrice,
20433
+ 6
20434
+ )} per share`
20435
+ );
20436
+ lines.push(
20437
+ ` supply ${simulation.current.junior.totalSupply} -> ${simulation.projected.junior.totalSupply}, value ${simulation.current.junior.value} -> ${simulation.projected.junior.value}`
20438
+ );
20439
+ }
20440
+ if (simulation.current.senior && simulation.projected.senior) {
20441
+ lines.push(
20442
+ ` senior: ${formatTransition(
20443
+ simulation.current.senior.sharePrice,
20444
+ simulation.projected.senior.sharePrice,
20445
+ 6
20446
+ )} per share`
20447
+ );
20448
+ lines.push(
20449
+ ` supply ${simulation.current.senior.totalSupply} -> ${simulation.projected.senior.totalSupply}, value ${simulation.current.senior.value} -> ${simulation.projected.senior.value}`
20450
+ );
20451
+ }
20452
+ }
20453
+ if (simulation.performanceFees) {
20454
+ lines.push(
20455
+ ` performance fees: curator=${simulation.performanceFees.curator} protocol=${simulation.performanceFees.protocol} total=${simulation.performanceFees.total} fee_shares=${simulation.performanceFees.mintedShares}`
20456
+ );
20457
+ }
20458
+ for (const blocker of simulation.blockers)
20459
+ lines.push(` BLOCKER: ${blocker}`);
20460
+ for (const warning of simulation.warnings)
20461
+ lines.push(` warning: ${warning}`);
20462
+ return lines;
20463
+ }
20464
+ function formatTransition(before, after, decimals) {
20465
+ return `${formatUnits(before, decimals)} [${before}] -> ${formatUnits(
20466
+ after,
20467
+ decimals
20468
+ )} [${after}]`;
20469
+ }
20470
+ function formatUnits(value, decimals) {
20471
+ const negative = value < 0n;
20472
+ const absolute = negative ? -value : value;
20473
+ const scale = 10n ** BigInt(decimals);
20474
+ const whole = absolute / scale;
20475
+ const fraction = (absolute % scale).toString().padStart(decimals, "0").replace(/0+$/, "");
20476
+ return `${negative ? "-" : ""}${whole}${fraction ? `.${fraction}` : ""}`;
20477
+ }
20478
+
20479
+ // src/services/consensusOracle/consensusOracleService.ts
19576
20480
  var SYSTEM_PROGRAM2 = "11111111111111111111111111111111";
19577
20481
  var CONSENSUS_ORACLE_VARIANT = "consensusoracle";
19578
20482
  function variantName2(value) {
@@ -19582,8 +20486,8 @@ function variantName2(value) {
19582
20486
  function coerceBool3(value) {
19583
20487
  if (typeof value === "boolean") return value;
19584
20488
  if (typeof value === "number") return value !== 0;
19585
- const record = value;
19586
- return Boolean(record?.value ?? record?.[0]);
20489
+ const record2 = value;
20490
+ return Boolean(record2?.value ?? record2?.[0]);
19587
20491
  }
19588
20492
  function priceInAccountingUnit(usd, baseUsd, assetDecimals) {
19589
20493
  return BigInt(Math.round(usd / baseUsd * 10 ** assetDecimals));
@@ -19605,7 +20509,7 @@ function parseExternalLiquidityRefs(vaultState) {
19605
20509
  if (!data || data.length < 40) continue;
19606
20510
  if (data[0] !== 1) continue;
19607
20511
  const pubkeyBytes = new Uint8Array(data.slice(8, 40));
19608
- const userAccount = new import_web326.PublicKey(pubkeyBytes).toBase58();
20512
+ const userAccount = new import_web327.PublicKey(pubkeyBytes).toBase58();
19609
20513
  refs.push({
19610
20514
  kind: "marginfi",
19611
20515
  mint: "",
@@ -19630,23 +20534,60 @@ var ConsensusOracleService = class {
19630
20534
  });
19631
20535
  const dryRun = opts.dryRun ?? false;
19632
20536
  const vaultState = await this.fetchDecodedVault(target.vault);
19633
- const consensusHoldings = selectConsensusHoldings(vaultState.holdings);
20537
+ const receiptMints = await this.fetchReceiptMints(target.vault, vaultState);
20538
+ const consensusHoldings = selectConsensusHoldings(
20539
+ vaultState.holdings,
20540
+ receiptMints
20541
+ );
20542
+ const filteredCount = vaultState.holdings.filter(
20543
+ (holding) => receiptMints.has((0, import_common41.fromWeb3Pk)(holding.mint).toString())
20544
+ ).length;
20545
+ if (filteredCount > 0) {
20546
+ log(
20547
+ `vault ${target.vault}: excluded ${filteredCount} vault/tranche receipt mint holding(s)`
20548
+ );
20549
+ }
19634
20550
  if (consensusHoldings.length === 0) {
19635
20551
  log(`vault ${target.vault}: no consensus holdings, skipping`);
19636
20552
  return { vault: target.vault, updates: [], dryRun };
19637
20553
  }
19638
- await this.assertNoUnconfirmedYieldPayments(target);
20554
+ const filteredTarget = filterTargetHoldings(target, receiptMints);
20555
+ await this.assertNoUnconfirmedYieldPayments(filteredTarget);
19639
20556
  const inputs = await this.gatherPricingInputs(
19640
- target,
20557
+ filteredTarget,
19641
20558
  vaultState,
19642
20559
  consensusHoldings
19643
20560
  );
19644
20561
  const updates = await this.buildUpdates(consensusHoldings, inputs);
19645
20562
  if (dryRun) {
19646
20563
  log(`vault ${target.vault}: dry run, ${updates.length} holding(s)`);
19647
- return { vault: target.vault, updates, dryRun: true };
20564
+ try {
20565
+ const settlementSimulation = await this.simulateDryRunSettlement(
20566
+ signer,
20567
+ target.vault,
20568
+ vaultState,
20569
+ updates
20570
+ );
20571
+ return {
20572
+ vault: target.vault,
20573
+ updates,
20574
+ dryRun: true,
20575
+ settlementSimulation
20576
+ };
20577
+ } catch (error) {
20578
+ const settlementSimulationError = error instanceof Error ? error.message : String(error);
20579
+ log(
20580
+ `vault ${target.vault}: settlement simulation unavailable: ${settlementSimulationError}`
20581
+ );
20582
+ return {
20583
+ vault: target.vault,
20584
+ updates,
20585
+ dryRun: true,
20586
+ settlementSimulationError
20587
+ };
20588
+ }
19648
20589
  }
19649
- const { updateSignature, crankSignature, crankSkippedReason } = await this.settleVault(signer, target, updates, vaultState, log);
20590
+ const { updateSignature, crankSignature, crankSkippedReason } = await this.settleVault(signer, filteredTarget, updates, vaultState, log);
19650
20591
  return {
19651
20592
  vault: target.vault,
19652
20593
  updates,
@@ -19656,6 +20597,43 @@ var ConsensusOracleService = class {
19656
20597
  crankSkippedReason
19657
20598
  };
19658
20599
  }
20600
+ /** Read canonical supplies and replay the exact on-chain settlement path. */
20601
+ async simulateDryRunSettlement(signer, vault, vaultState, updates) {
20602
+ const tranchingEnabled = coerceBool3(vaultState.tranchingEnabled);
20603
+ const [oracleState, trancheState] = await Promise.all([
20604
+ this.client.account.fetchVaultOracleForVault(vault, { fresh: true }),
20605
+ tranchingEnabled ? this.client.account.fetchVaultTrancheStateForVault(vault, {
20606
+ fresh: true
20607
+ }) : Promise.resolve(void 0)
20608
+ ]);
20609
+ const mintKeys = [new import_web327.PublicKey(vaultState.mint)];
20610
+ if (trancheState) {
20611
+ mintKeys.push(
20612
+ new import_web327.PublicKey(trancheState.config.juniorMint),
20613
+ new import_web327.PublicKey(trancheState.config.seniorMint)
20614
+ );
20615
+ }
20616
+ const mintAccounts = await this.client.provider.connection.getMultipleAccountsInfo(
20617
+ mintKeys,
20618
+ "confirmed"
20619
+ );
20620
+ const supplies = mintAccounts.map((info, index) => {
20621
+ if (!info)
20622
+ throw new Error(`share mint ${mintKeys[index]} does not exist`);
20623
+ return readSplMintSupply(info.data);
20624
+ });
20625
+ return simulateConsensusOracleSettlement({
20626
+ vault: vaultState,
20627
+ oracleData: oracleState.data,
20628
+ trancheState,
20629
+ updates,
20630
+ signer: (0, import_common41.fromWeb3Pk)(signer.publicKey),
20631
+ nowTs: BigInt(Math.floor(this.clock.now() / 1e3)),
20632
+ physicalShareSupply: supplies[0],
20633
+ physicalJuniorSupply: tranchingEnabled ? supplies[1] : void 0,
20634
+ physicalSeniorSupply: tranchingEnabled ? supplies[2] : void 0
20635
+ });
20636
+ }
19659
20637
  /**
19660
20638
  * Fail closed while any configured yield account has an unsettled payment.
19661
20639
  * The payout must be confirmed only after it is visible in the same wallet
@@ -19777,6 +20755,28 @@ var ConsensusOracleService = class {
19777
20755
  fresh: true
19778
20756
  });
19779
20757
  }
20758
+ /**
20759
+ * Receipt mints issued by this vault are liabilities/shares, not underlying
20760
+ * assets for its own NAV. Exclude them even if they were registered as
20761
+ * consensus-priced holdings.
20762
+ */
20763
+ async fetchReceiptMints(vault, vaultState) {
20764
+ const receiptMints = /* @__PURE__ */ new Set();
20765
+ if (vaultState.mint) {
20766
+ receiptMints.add((0, import_common41.fromWeb3Pk)(vaultState.mint).toString());
20767
+ }
20768
+ if (!coerceBool3(vaultState.tranchingEnabled)) return receiptMints;
20769
+ const trancheState = await this.client.account.fetchVaultTrancheStateForVault(vault, {
20770
+ fresh: true
20771
+ });
20772
+ receiptMints.add(
20773
+ (0, import_common41.fromWeb3Pk)(trancheState.config.juniorMint).toString()
20774
+ );
20775
+ receiptMints.add(
20776
+ (0, import_common41.fromWeb3Pk)(trancheState.config.seniorMint).toString()
20777
+ );
20778
+ return receiptMints;
20779
+ }
19780
20780
  /** Fetch every external input the per-holding updates draw on, in parallel-ish. */
19781
20781
  async gatherPricingInputs(target, vaultState, consensusHoldings) {
19782
20782
  const manager = (0, import_common41.fromWeb3Pk)(vaultState.roles.manager);
@@ -19948,8 +20948,8 @@ var ConsensusOracleService = class {
19948
20948
  const nowSecs = BigInt(Math.floor(this.clock.now() / 1e3));
19949
20949
  const elapsedSecs = nowSecs - settledNavTs;
19950
20950
  if (elapsedSecs <= 0n) return;
19951
- const SECONDS_PER_YEAR2 = 365n * 24n * 3600n;
19952
- const apyBps = (prospectiveNav - settledNav) * SECONDS_PER_YEAR2 * 10000n / (settledNav * elapsedSecs);
20951
+ const SECONDS_PER_YEAR3 = 365n * 24n * 3600n;
20952
+ const apyBps = (prospectiveNav - settledNav) * SECONDS_PER_YEAR3 * 10000n / (settledNav * elapsedSecs);
19953
20953
  log(
19954
20954
  `vault ${vault}: prospective NAV ${prospectiveNav} vs settled ${settledNav} (elapsed ${elapsedSecs}s) \u2192 implied APY ${apyBps}bps`
19955
20955
  );
@@ -19965,13 +20965,23 @@ function readI64LE(data, offset) {
19965
20965
  if (value >= 0x8000000000000000n) value -= 0x10000000000000000n;
19966
20966
  return value;
19967
20967
  }
19968
- var ENTRY_SIZE = 272;
19969
- var ENTRIES_OFFSET = 40;
20968
+ function readSplMintSupply(data) {
20969
+ if (data.length < 44) {
20970
+ throw new Error(`invalid SPL mint account: expected at least 44 bytes`);
20971
+ }
20972
+ let supply = 0n;
20973
+ for (let i = 0; i < 8; i += 1) {
20974
+ supply |= BigInt(data[36 + i]) << BigInt(8 * i);
20975
+ }
20976
+ return supply;
20977
+ }
20978
+ var ENTRY_SIZE2 = 272;
20979
+ var ENTRIES_OFFSET2 = 40;
19970
20980
  var MAX_CONSENSUS_SIGNERS = 4;
19971
20981
  function signerInOracleData(data, signerBytes) {
19972
20982
  const ZERO_PUBKEY = new Uint8Array(32);
19973
20983
  for (let i = 0; i < MAX_CONSENSUS_SIGNERS; i++) {
19974
- const off = ENTRIES_OFFSET + i * ENTRY_SIZE;
20984
+ const off = ENTRIES_OFFSET2 + i * ENTRY_SIZE2;
19975
20985
  const slice = data.slice(off, off + 32);
19976
20986
  if (slice.length < 32) break;
19977
20987
  const bytes = new Uint8Array(slice);
@@ -19981,12 +20991,21 @@ function signerInOracleData(data, signerBytes) {
19981
20991
  }
19982
20992
  return false;
19983
20993
  }
19984
- function selectConsensusHoldings(holdings) {
20994
+ function selectConsensusHoldings(holdings, excludedMints = /* @__PURE__ */ new Set()) {
19985
20995
  return holdings.map((holding, holdingIndex) => ({ holding, holdingIndex })).filter(({ holding }) => {
19986
20996
  const mint = (0, import_common41.fromWeb3Pk)(holding.mint);
19987
- return mint !== SYSTEM_PROGRAM2 && variantName2(holding.priceOracleType).toLowerCase() === CONSENSUS_ORACLE_VARIANT;
20997
+ return mint !== SYSTEM_PROGRAM2 && !excludedMints.has(mint.toString()) && variantName2(holding.priceOracleType).toLowerCase() === CONSENSUS_ORACLE_VARIANT;
19988
20998
  });
19989
20999
  }
21000
+ function filterTargetHoldings(target, excludedMints) {
21001
+ if (!target.holdings?.length || excludedMints.size === 0) return target;
21002
+ return {
21003
+ ...target,
21004
+ holdings: target.holdings.filter(
21005
+ (holding) => !excludedMints.has(holding.mint.toString())
21006
+ )
21007
+ };
21008
+ }
19990
21009
 
19991
21010
  // src/services/consensusOracle/runLiveConsensusOracle.ts
19992
21011
  async function runLiveConsensusOracle(env, oracleSigner, opts = {}) {
@@ -20010,7 +21029,7 @@ async function runLiveConsensusOracle(env, oracleSigner, opts = {}) {
20010
21029
  }
20011
21030
 
20012
21031
  // src/services/consensusOracle/mockYieldTracker.ts
20013
- var SECONDS_PER_YEAR = 365 * 24 * 60 * 60;
21032
+ var SECONDS_PER_YEAR2 = 365 * 24 * 60 * 60;
20014
21033
  var MockYieldTracker = class {
20015
21034
  constructor(opts = {}) {
20016
21035
  this.accounts = /* @__PURE__ */ new Map();
@@ -20065,12 +21084,12 @@ var MockYieldTracker = class {
20065
21084
  let segStart = windowStartMs;
20066
21085
  for (const cf of boundaries) {
20067
21086
  const dtSecs = (cf.ts - segStart) / 1e3;
20068
- totalYield += principal * apr * (dtSecs / SECONDS_PER_YEAR);
21087
+ totalYield += principal * apr * (dtSecs / SECONDS_PER_YEAR2);
20069
21088
  principal += cf.amount;
20070
21089
  segStart = cf.ts;
20071
21090
  }
20072
21091
  const tailSecs = Math.max(0, (windowEndMs - segStart) / 1e3);
20073
- totalYield += principal * apr * (tailSecs / SECONDS_PER_YEAR);
21092
+ totalYield += principal * apr * (tailSecs / SECONDS_PER_YEAR2);
20074
21093
  const paidYield = state.yieldPayments.reduce((sum, payment) => {
20075
21094
  return payment.status === "confirmed" && payment.effectiveAt > windowStartMs && payment.effectiveAt <= windowEndMs ? sum + payment.amount : sum;
20076
21095
  }, 0);
@@ -20090,22 +21109,22 @@ var MockYieldTracker = class {
20090
21109
  async getTotalYield(accountNames, start, end) {
20091
21110
  let total = 0;
20092
21111
  for (const name of accountNames) {
20093
- const snapshot = await this.getYield(name, start, end);
20094
- total += snapshot.totalYield;
21112
+ const snapshot2 = await this.getYield(name, start, end);
21113
+ total += snapshot2.totalYield;
20095
21114
  }
20096
21115
  return total;
20097
21116
  }
20098
21117
  async getTotalOutstandingYield(accountNames, start, end) {
20099
21118
  let total = 0;
20100
21119
  for (const name of accountNames) {
20101
- const snapshot = await this.getYield(name, start, end);
20102
- total += snapshot.outstandingYield;
21120
+ const snapshot2 = await this.getYield(name, start, end);
21121
+ total += snapshot2.outstandingYield;
20103
21122
  }
20104
21123
  return total;
20105
21124
  }
20106
21125
  async getBalance(accountName, atTime) {
20107
- const snapshot = await this.getYield(accountName, void 0, atTime);
20108
- return snapshot.principalAtEnd + snapshot.outstandingYield;
21126
+ const snapshot2 = await this.getYield(accountName, void 0, atTime);
21127
+ return snapshot2.principalAtEnd + snapshot2.outstandingYield;
20109
21128
  }
20110
21129
  async addCashflow(params) {
20111
21130
  const state = this.require(params.accountName);
@@ -20157,12 +21176,12 @@ var MockYieldTracker = class {
20157
21176
  let cumulativePaid = 0;
20158
21177
  for (const candidate of chronologicalPayments) {
20159
21178
  cumulativePaid += candidate.amount;
20160
- const snapshot = await this.getYield(
21179
+ const snapshot2 = await this.getYield(
20161
21180
  params.accountName,
20162
21181
  void 0,
20163
21182
  new Date(candidate.effectiveAt)
20164
21183
  );
20165
- if (cumulativePaid > snapshot.totalYield + 1e-9) {
21184
+ if (cumulativePaid > snapshot2.totalYield + 1e-9) {
20166
21185
  throw new Error("Confirmed payment exceeds accrued unpaid yield");
20167
21186
  }
20168
21187
  }
@@ -20172,8 +21191,8 @@ var MockYieldTracker = class {
20172
21191
  };
20173
21192
 
20174
21193
  // src/services/externalLiquidityIntegrityService.ts
20175
- var import_kit13 = require("@solana/kit");
20176
- var import_web327 = require("@solana/web3.js");
21194
+ var import_kit15 = require("@solana/kit");
21195
+ var import_web328 = require("@solana/web3.js");
20177
21196
  var import_common42 = __toESM(require_dist());
20178
21197
  var import_marginfi2 = __toESM(require_dist2());
20179
21198
  function parseActiveSlots(externalLiquidity) {
@@ -20186,7 +21205,7 @@ function parseActiveSlots(externalLiquidity) {
20186
21205
  if (discriminant === 0) continue;
20187
21206
  if (discriminant !== 1) continue;
20188
21207
  const pubkeyBytes = new Uint8Array(data.slice(8, 40));
20189
- const userAccount = (0, import_common42.toAddress)(new import_web327.PublicKey(pubkeyBytes));
21208
+ const userAccount = (0, import_common42.toAddress)(new import_web328.PublicKey(pubkeyBytes));
20190
21209
  results.push({ index: i, source: "marginfi", userAccount });
20191
21210
  }
20192
21211
  return results;
@@ -20252,7 +21271,7 @@ var ExternalLiquidityIntegrityService = class {
20252
21271
  return result;
20253
21272
  }
20254
21273
  const hwManagerAddress = (0, import_common42.fromWeb3Pk)(hwManager.publicKey);
20255
- const vaultPk = new import_web327.PublicKey(vault.toString());
21274
+ const vaultPk = new import_web328.PublicKey(vault.toString());
20256
21275
  const registeredHwManager = pubkeyStr(
20257
21276
  vaultState.roles.hwManager
20258
21277
  );
@@ -20279,7 +21298,7 @@ var ExternalLiquidityIntegrityService = class {
20279
21298
  continue;
20280
21299
  }
20281
21300
  for (const holding of holdings) {
20282
- const mintAddress = (0, import_kit13.address)(pubkeyStr(holding.mint));
21301
+ const mintAddress = (0, import_kit15.address)(pubkeyStr(holding.mint));
20283
21302
  const localAmount = toBigInt2(holding.localAmount);
20284
21303
  const marginfiAccounts = (0, import_marginfi2.marginfiAccountsForMint)(mintAddress);
20285
21304
  if (!marginfiAccounts) {
@@ -20395,11 +21414,17 @@ var ExternalLiquidityIntegrityService = class {
20395
21414
  JupiterPriceSource,
20396
21415
  JupiterSwapBuilder,
20397
21416
  KaminoPositionProvider,
21417
+ LOCAL_PROTOCOL_ADMIN,
21418
+ LivePriceSource,
20398
21419
  MAX_PRICE_STALENESS_THRESHOLD_SECS,
20399
21420
  ManagerRedepositAssetBuilder,
20400
21421
  ManagerWithdrawAssetBuilder,
20401
21422
  MarginfiPositionProvider,
20402
21423
  MockYieldTracker,
21424
+ NEST_API_BASE_URL,
21425
+ NEST_RWA_SHARE_MINT,
21426
+ NEST_VAULT_SLUG,
21427
+ NestPriceSource,
20403
21428
  OracleService,
20404
21429
  PROGRAM_FEE_EXEMPT_OWNER_WHITELIST,
20405
21430
  PROTOCOL_ADMIN,
@@ -20442,6 +21467,7 @@ var ExternalLiquidityIntegrityService = class {
20442
21467
  WithdrawalQueueService,
20443
21468
  addCashflowUpdate,
20444
21469
  address,
21470
+ applyEffectiveApy,
20445
21471
  confirmYieldPayment,
20446
21472
  createAccount,
20447
21473
  createLiveConsensusOracleDeps,
@@ -20453,7 +21479,9 @@ var ExternalLiquidityIntegrityService = class {
20453
21479
  dateToStr,
20454
21480
  defaultKeypairPath,
20455
21481
  deleteAccount,
21482
+ fetchNestTokenPrice,
20456
21483
  findSquadsWalletRoute,
21484
+ formatSettlementSimulation,
20457
21485
  fromUiAmount,
20458
21486
  getAccounts,
20459
21487
  getBalance,
@@ -20474,6 +21502,7 @@ var ExternalLiquidityIntegrityService = class {
20474
21502
  resolveSquadsWalletRoute,
20475
21503
  roundToNextUtcMidnight,
20476
21504
  runLiveConsensusOracle,
21505
+ simulateConsensusOracleSettlement,
20477
21506
  systemClock,
20478
21507
  toUiAmount,
20479
21508
  updateAccount,