@percolatorct/sdk 1.0.0-beta.12 → 1.0.0-beta.14

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
@@ -1,13 +1,16 @@
1
1
  // src/abi/encode.ts
2
2
  import { PublicKey } from "@solana/web3.js";
3
+ var U8_MAX = 255;
4
+ var U16_MAX = 65535;
5
+ var U32_MAX = 4294967295;
3
6
  function encU8(val) {
4
- if (!Number.isInteger(val) || val < 0 || val > 255) {
7
+ if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {
5
8
  throw new Error(`encU8: value out of range (0..255), got ${val}`);
6
9
  }
7
10
  return new Uint8Array([val]);
8
11
  }
9
12
  function encU16(val) {
10
- if (!Number.isInteger(val) || val < 0 || val > 65535) {
13
+ if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {
11
14
  throw new Error(`encU16: value out of range (0..65535), got ${val}`);
12
15
  }
13
16
  const buf = new Uint8Array(2);
@@ -15,7 +18,7 @@ function encU16(val) {
15
18
  return buf;
16
19
  }
17
20
  function encU32(val) {
18
- if (!Number.isInteger(val) || val < 0 || val > 4294967295) {
21
+ if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {
19
22
  throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);
20
23
  }
21
24
  const buf = new Uint8Array(4);
@@ -131,13 +134,8 @@ var IX_TAG = {
131
134
  ReclaimEmptyAccount: 25,
132
135
  SettleAccount: 26,
133
136
  // Tags 27-28: on-chain = DepositFeeCredits/ConvertReleasedPnl.
134
- // Legacy aliases (PauseMarket/UnpauseMarket) kept — those instructions don't exist on-chain.
135
137
  DepositFeeCredits: 27,
136
- /** @deprecated No on-chain PauseMarket instruction */
137
- PauseMarket: 27,
138
138
  ConvertReleasedPnl: 28,
139
- /** @deprecated No on-chain UnpauseMarket instruction */
140
- UnpauseMarket: 28,
141
139
  // Tags 29-30: on-chain = ResolvePermissionless/ForceCloseResolved.
142
140
  ResolvePermissionless: 29,
143
141
  /** @deprecated Use ResolvePermissionless */
@@ -225,7 +223,13 @@ var IX_TAG = {
225
223
  /** PERC-SetDexPool: Pin admin-approved DEX pool address for a HYPERP market (admin). */
226
224
  SetDexPool: 74,
227
225
  /** CPI to the matcher program to initialize a matcher context account for an LP slot. Admin-only. */
228
- InitMatcherCtx: 75
226
+ InitMatcherCtx: 75,
227
+ /** PauseMarket (tag 76): admin emergency pause. Blocks Trade/Deposit/Withdraw/InitUser. */
228
+ PauseMarket: 76,
229
+ /** UnpauseMarket (tag 77): admin unpause. Re-enables all operations. */
230
+ UnpauseMarket: 77,
231
+ /** CloseKeeperFund (tag 78): close keeper fund PDA and recover lamports to admin. */
232
+ CloseKeeperFund: 78
229
233
  };
230
234
  Object.freeze(IX_TAG);
231
235
  var HEX_RE = /^[0-9a-fA-F]{64}$/;
@@ -264,19 +268,23 @@ function encodeInitMarket(args) {
264
268
  encU128(args.maxMaintenanceFeePerSlot ?? 0n),
265
269
  encU128(args.maxInsuranceFloor ?? 0n),
266
270
  encU64(args.minOraclePriceCap ?? 0n),
267
- // RiskParams block (15 fields)
271
+ // RiskParams wire format — must match read_risk_params() in percolator.rs
272
+ // Note: insurance_floor occupies the old riskReductionThreshold slot,
273
+ // and liquidationBufferBps is read but discarded (kept for wire compat).
268
274
  encU64(args.warmupPeriodSlots),
269
275
  encU64(args.maintenanceMarginBps),
270
276
  encU64(args.initialMarginBps),
271
277
  encU64(args.tradingFeeBps),
272
278
  encU64(args.maxAccounts),
273
279
  encU128(args.newAccountFee),
274
- encU128(args.riskReductionThreshold),
280
+ encU128(args.insuranceFloor ?? 0n),
281
+ // wire slot: old riskReductionThreshold → now insurance_floor
275
282
  encU128(args.maintenanceFeePerSlot),
276
283
  encU64(args.maxCrankStalenessSlots),
277
284
  encU64(args.liquidationFeeBps),
278
285
  encU128(args.liquidationFeeCap),
279
- encU64(args.liquidationBufferBps),
286
+ encU64(args.liquidationBufferBps ?? 0n),
287
+ // wire slot: read and discarded by program
280
288
  encU128(args.minLiquidationAbs),
281
289
  encU128(args.minInitialDeposit),
282
290
  encU128(args.minNonzeroMmReq),
@@ -480,12 +488,12 @@ function encodeSetPythOracle(args) {
480
488
  }
481
489
  var PYTH_RECEIVER_PROGRAM_ID = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ";
482
490
  async function derivePythPriceUpdateAccount(feedId, shardId = 0) {
483
- const { PublicKey: PublicKey15 } = await import("@solana/web3.js");
491
+ const { PublicKey: PublicKey14 } = await import("@solana/web3.js");
484
492
  const shardBuf = new Uint8Array(2);
485
493
  new DataView(shardBuf.buffer).setUint16(0, shardId, true);
486
- const [pda] = PublicKey15.findProgramAddressSync(
494
+ const [pda] = PublicKey14.findProgramAddressSync(
487
495
  [shardBuf, feedId],
488
- new PublicKey15(PYTH_RECEIVER_PROGRAM_ID)
496
+ new PublicKey14(PYTH_RECEIVER_PROGRAM_ID)
489
497
  );
490
498
  return pda.toBase58();
491
499
  }
@@ -720,6 +728,18 @@ function encodeCloseOrphanSlab() {
720
728
  function encodeSetDexPool(args) {
721
729
  return concatBytes(encU8(IX_TAG.SetDexPool), encPubkey(args.pool));
722
730
  }
731
+ function encodeCloseKeeperFund() {
732
+ return concatBytes(encU8(IX_TAG.CloseKeeperFund));
733
+ }
734
+ function encodeCreateInsuranceMint() {
735
+ return encodeCreateLpVault({ feeShareBps: 0n });
736
+ }
737
+ function encodeDepositInsuranceLP(args) {
738
+ return encodeLpVaultDeposit({ amount: args.amount });
739
+ }
740
+ function encodeWithdrawInsuranceLP(args) {
741
+ return encodeLpVaultWithdraw({ lpAmount: args.lpAmount });
742
+ }
723
743
 
724
744
  // src/abi/accounts.ts
725
745
  import {
@@ -744,7 +764,8 @@ var ACCOUNTS_INIT_USER = [
744
764
  { name: "slab", signer: false, writable: true },
745
765
  { name: "userAta", signer: false, writable: true },
746
766
  { name: "vault", signer: false, writable: true },
747
- { name: "tokenProgram", signer: false, writable: false }
767
+ { name: "tokenProgram", signer: false, writable: false },
768
+ { name: "clock", signer: false, writable: false }
748
769
  ];
749
770
  var ACCOUNTS_INIT_LP = [
750
771
  { name: "user", signer: true, writable: true },
@@ -811,6 +832,7 @@ var ACCOUNTS_TRADE_CPI = [
811
832
  { name: "lpOwner", signer: false, writable: false },
812
833
  // LP delegated to matcher - no signature needed
813
834
  { name: "slab", signer: false, writable: true },
835
+ { name: "clock", signer: false, writable: false },
814
836
  { name: "oracle", signer: false, writable: false },
815
837
  { name: "matcherProg", signer: false, writable: false },
816
838
  { name: "matcherCtx", signer: false, writable: true },
@@ -894,6 +916,37 @@ function buildAccountMetas(spec, keys) {
894
916
  isWritable: s.writable
895
917
  }));
896
918
  }
919
+ var ACCOUNTS_CREATE_INSURANCE_MINT = [
920
+ { name: "admin", signer: true, writable: false },
921
+ { name: "slab", signer: false, writable: false },
922
+ { name: "insLpMint", signer: false, writable: true },
923
+ { name: "vaultAuthority", signer: false, writable: false },
924
+ { name: "collateralMint", signer: false, writable: false },
925
+ { name: "systemProgram", signer: false, writable: false },
926
+ { name: "tokenProgram", signer: false, writable: false },
927
+ { name: "rent", signer: false, writable: false },
928
+ { name: "payer", signer: true, writable: true }
929
+ ];
930
+ var ACCOUNTS_DEPOSIT_INSURANCE_LP = [
931
+ { name: "depositor", signer: true, writable: false },
932
+ { name: "slab", signer: false, writable: true },
933
+ { name: "depositorAta", signer: false, writable: true },
934
+ { name: "vault", signer: false, writable: true },
935
+ { name: "tokenProgram", signer: false, writable: false },
936
+ { name: "insLpMint", signer: false, writable: true },
937
+ { name: "depositorLpAta", signer: false, writable: true },
938
+ { name: "vaultAuthority", signer: false, writable: false }
939
+ ];
940
+ var ACCOUNTS_WITHDRAW_INSURANCE_LP = [
941
+ { name: "withdrawer", signer: true, writable: false },
942
+ { name: "slab", signer: false, writable: true },
943
+ { name: "withdrawerAta", signer: false, writable: true },
944
+ { name: "vault", signer: false, writable: true },
945
+ { name: "tokenProgram", signer: false, writable: false },
946
+ { name: "insLpMint", signer: false, writable: true },
947
+ { name: "withdrawerLpAta", signer: false, writable: true },
948
+ { name: "vaultAuthority", signer: false, writable: false }
949
+ ];
897
950
  var ACCOUNTS_LP_VAULT_WITHDRAW = [
898
951
  { name: "withdrawer", signer: true, writable: false },
899
952
  { name: "slab", signer: false, writable: true },
@@ -964,7 +1017,8 @@ var ACCOUNTS_ADVANCE_ORACLE_PHASE = [
964
1017
  var ACCOUNTS_TOPUP_KEEPER_FUND = [
965
1018
  { name: "funder", signer: true, writable: true },
966
1019
  { name: "slab", signer: false, writable: true },
967
- { name: "keeperFund", signer: false, writable: true }
1020
+ { name: "keeperFund", signer: false, writable: true },
1021
+ { name: "systemProgram", signer: false, writable: false }
968
1022
  ];
969
1023
  var ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK = [
970
1024
  { name: "admin", signer: true, writable: false },
@@ -1015,6 +1069,11 @@ var ACCOUNTS_SET_WALLET_CAP = [
1015
1069
  { name: "admin", signer: true, writable: false },
1016
1070
  { name: "slab", signer: false, writable: true }
1017
1071
  ];
1072
+ var ACCOUNTS_SET_DEX_POOL = [
1073
+ { name: "admin", signer: true, writable: false },
1074
+ { name: "slab", signer: false, writable: true },
1075
+ { name: "poolAccount", signer: false, writable: false }
1076
+ ];
1018
1077
  var ACCOUNTS_INIT_MATCHER_CTX = [
1019
1078
  { name: "admin", signer: true, writable: false },
1020
1079
  { name: "slab", signer: false, writable: false },
@@ -1306,24 +1365,11 @@ function getErrorName(code) {
1306
1365
  function getErrorHint(code) {
1307
1366
  return PERCOLATOR_ERRORS[code]?.hint;
1308
1367
  }
1309
- var LIGHTHOUSE_PROGRAM_ID_STR = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
1310
- var ANCHOR_ERROR_RANGE_START = 6e3;
1311
- var ANCHOR_ERROR_RANGE_END = 8191;
1312
- var ANCHOR_ERROR_NAMES = {
1313
- 6032: "ConstraintMut",
1314
- 6036: "ConstraintOwner",
1315
- 6038: "ConstraintSeeds",
1316
- 6400: "ConstraintAddress"
1317
- };
1318
- function isAnchorErrorCode(code) {
1319
- return code >= ANCHOR_ERROR_RANGE_START && code <= ANCHOR_ERROR_RANGE_END;
1320
- }
1321
1368
  var CUSTOM_ERROR_HEX_MAX_LEN = 8;
1322
1369
  function parseErrorFromLogs(logs) {
1323
1370
  if (!Array.isArray(logs)) {
1324
1371
  return null;
1325
1372
  }
1326
- let insideLighthouse = false;
1327
1373
  const re = new RegExp(
1328
1374
  `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,
1329
1375
  "i"
@@ -1332,32 +1378,17 @@ function parseErrorFromLogs(logs) {
1332
1378
  if (typeof log !== "string") {
1333
1379
  continue;
1334
1380
  }
1335
- if (log.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {
1336
- insideLighthouse = true;
1337
- } else if (log.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {
1338
- insideLighthouse = false;
1339
- }
1340
1381
  const match = log.match(re);
1341
1382
  if (match) {
1342
1383
  const code = parseInt(match[1], 16);
1343
1384
  if (!Number.isFinite(code) || code < 0 || code > 4294967295) {
1344
1385
  continue;
1345
1386
  }
1346
- if (isAnchorErrorCode(code) || insideLighthouse) {
1347
- const anchorName = ANCHOR_ERROR_NAMES[code] ?? `AnchorError(0x${code.toString(16)})`;
1348
- return {
1349
- code,
1350
- name: `Lighthouse:${anchorName}`,
1351
- hint: "This error comes from the Lighthouse/Blowfish wallet guard, not from Percolator. The transaction itself is valid. Disable transaction simulation in your wallet settings, or use a wallet without Blowfish protection (e.g., Backpack, Solflare).",
1352
- source: "lighthouse"
1353
- };
1354
- }
1355
1387
  const info = decodeError(code);
1356
1388
  return {
1357
1389
  code,
1358
1390
  name: info?.name ?? `Unknown(${code})`,
1359
- hint: info?.hint,
1360
- source: info ? "percolator" : "unknown"
1391
+ hint: info?.hint
1361
1392
  };
1362
1393
  }
1363
1394
  }
@@ -1573,7 +1604,25 @@ var V12_1_ACCOUNT_SIZE_SBF = 280;
1573
1604
  var V12_1_ENGINE_BITMAP_OFF = 1016;
1574
1605
  var V12_1_ENGINE_PARAMS_OFF_SBF = 32;
1575
1606
  var V12_1_ENGINE_PARAMS_OFF_HOST = 96;
1607
+ var V12_1_PARAMS_SIZE_SBF = 184;
1576
1608
  var V12_1_PARAMS_SIZE = 352;
1609
+ var V12_1_SBF_OFF_CURRENT_SLOT = 216;
1610
+ var V12_1_SBF_OFF_FUNDING_RATE = 224;
1611
+ var V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;
1612
+ var V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;
1613
+ var V12_1_SBF_OFF_C_TOT = 248;
1614
+ var V12_1_SBF_OFF_PNL_POS_TOT = 264;
1615
+ var V12_1_SBF_OFF_LIQ_CURSOR = 296;
1616
+ var V12_1_SBF_OFF_GC_CURSOR = 298;
1617
+ var V12_1_SBF_OFF_LAST_SWEEP_START = 304;
1618
+ var V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;
1619
+ var V12_1_SBF_OFF_CRANK_CURSOR = 320;
1620
+ var V12_1_SBF_OFF_SWEEP_START_IDX = 322;
1621
+ var V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;
1622
+ var V12_1_SBF_OFF_TOTAL_OI = 448;
1623
+ var V12_1_SBF_OFF_LONG_OI = 464;
1624
+ var V12_1_SBF_OFF_SHORT_OI = 480;
1625
+ var V12_1_SBF_OFF_MARK_PRICE_E6 = 560;
1577
1626
  var V12_1_ENGINE_CURRENT_SLOT_OFF = 448;
1578
1627
  var V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;
1579
1628
  var V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;
@@ -1608,7 +1657,13 @@ var V12_1_ACCT_FEE_CREDITS_OFF = 240;
1608
1657
  var V12_1_ACCT_LAST_FEE_SLOT_OFF = 256;
1609
1658
  var V12_1_ACCT_POSITION_SIZE_OFF = 88;
1610
1659
  var V12_1_ACCT_ENTRY_PRICE_OFF = -1;
1611
- var V12_1_ACCT_FUNDING_INDEX_OFF = 288;
1660
+ var V12_1_EP_SBF_ACCOUNT_SIZE = 288;
1661
+ var V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;
1662
+ var V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;
1663
+ var V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;
1664
+ var V12_1_EP_ACCT_OWNER_OFF = 216;
1665
+ var V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;
1666
+ var V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;
1612
1667
  var V1M_ENGINE_OFF = 640;
1613
1668
  var V1M_CONFIG_LEN = 536;
1614
1669
  var V1M_ACCOUNT_SIZE = 248;
@@ -1683,14 +1738,23 @@ for (const n of TIERS) {
1683
1738
  V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);
1684
1739
  }
1685
1740
  var V12_1_SBF_ACCOUNT_SIZE = 280;
1686
- var V12_1_SBF_ENGINE_PREAMBLE = 558;
1741
+ var V12_1_SBF_ENGINE_OFF = 616;
1742
+ var V12_1_SBF_BITMAP_OFF = 584;
1687
1743
  for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
1688
1744
  const bitmapBytes = Math.ceil(n / 64) * 8;
1689
- const preAccLen = V12_1_SBF_ENGINE_PREAMBLE + bitmapBytes + 18 + n * 2;
1745
+ const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;
1690
1746
  const accountsOff = Math.ceil(preAccLen / 8) * 8;
1691
- const total = V12_1_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;
1747
+ const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;
1692
1748
  V12_1_SIZES.set(total, n);
1693
1749
  }
1750
+ var V12_1_EP_SIZES = /* @__PURE__ */ new Map();
1751
+ for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
1752
+ const bitmapBytes = Math.ceil(n / 64) * 8;
1753
+ const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;
1754
+ const accountsOff = Math.ceil(preAccLen / 8) * 8;
1755
+ const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;
1756
+ V12_1_EP_SIZES.set(total, n);
1757
+ }
1694
1758
  var SLAB_TIERS_V2 = {
1695
1759
  small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V2 BPF intermediate)" },
1696
1760
  large: { maxAccounts: 4096, dataSize: 1025568, label: "Large", description: "4,096 slots (V2 BPF intermediate)" }
@@ -2218,8 +2282,8 @@ function buildLayoutVSetDexPool(maxAccounts) {
2218
2282
  function buildLayoutV12_1(maxAccounts, dataLen) {
2219
2283
  const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);
2220
2284
  const isSbf = dataLen !== void 0 && dataLen !== hostSize;
2221
- const engineOff = isSbf ? 616 : V12_1_ENGINE_OFF;
2222
- const bitmapOff = isSbf ? 590 : V12_1_ENGINE_BITMAP_OFF - V12_1_ENGINE_OFF;
2285
+ const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;
2286
+ const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF - V12_1_ENGINE_OFF;
2223
2287
  const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;
2224
2288
  const bitmapWords = Math.ceil(maxAccounts / 64);
2225
2289
  const bitmapBytes = bitmapWords * 8;
@@ -2229,14 +2293,11 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
2229
2293
  const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
2230
2294
  return {
2231
2295
  version: 1,
2232
- // V12_1 upstream rebase uses 72-byte header (SlabHeader only, no V1 extension).
2233
- // Empirically verified: USDC mint found at offset 72 on mainnet slab BVjPc6rd.
2234
2296
  headerLen: V0_HEADER_LEN,
2235
- // 72 (not 104 — V12_1 removed the 32-byte header extension)
2297
+ // 72
2236
2298
  configOffset: V0_HEADER_LEN,
2237
2299
  // 72
2238
2300
  configLen: isSbf ? 544 : 576,
2239
- // SBF=544, host=576 (alignment diff)
2240
2301
  reservedOff: V1_RESERVED_OFF,
2241
2302
  engineOff,
2242
2303
  accountSize,
@@ -2245,45 +2306,124 @@ function buildLayoutV12_1(maxAccounts, dataLen) {
2245
2306
  accountsOff: engineOff + accountsOffRel,
2246
2307
  engineInsuranceOff: 16,
2247
2308
  engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,
2248
- paramsSize: V12_1_PARAMS_SIZE,
2249
- // SBF shift: InsuranceFund=16B (was 80) + RiskParams=184B (was 352) = 232 bytes smaller.
2250
- // All engine fields after RiskParams are shifted by -232 on SBF.
2251
- engineCurrentSlotOff: isSbf ? V12_1_ENGINE_CURRENT_SLOT_OFF - 232 : V12_1_ENGINE_CURRENT_SLOT_OFF,
2252
- engineFundingIndexOff: isSbf ? V12_1_ENGINE_FUNDING_INDEX_OFF - 232 : V12_1_ENGINE_FUNDING_INDEX_OFF,
2253
- engineLastFundingSlotOff: isSbf ? V12_1_ENGINE_LAST_FUNDING_SLOT_OFF - 232 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF,
2254
- engineFundingRateBpsOff: isSbf ? V12_1_ENGINE_FUNDING_RATE_BPS_OFF - 232 : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,
2255
- engineMarkPriceOff: isSbf ? V12_1_ENGINE_MARK_PRICE_OFF - 232 : V12_1_ENGINE_MARK_PRICE_OFF,
2256
- engineLastCrankSlotOff: isSbf ? V12_1_ENGINE_LAST_CRANK_SLOT_OFF - 232 : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,
2257
- engineMaxCrankStalenessOff: isSbf ? V12_1_ENGINE_MAX_CRANK_STALENESS_OFF - 232 : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,
2258
- engineTotalOiOff: isSbf ? V12_1_ENGINE_TOTAL_OI_OFF - 232 : V12_1_ENGINE_TOTAL_OI_OFF,
2259
- engineLongOiOff: isSbf ? V12_1_ENGINE_LONG_OI_OFF - 232 : V12_1_ENGINE_LONG_OI_OFF,
2260
- engineShortOiOff: isSbf ? V12_1_ENGINE_SHORT_OI_OFF - 232 : V12_1_ENGINE_SHORT_OI_OFF,
2261
- engineCTotOff: isSbf ? V12_1_ENGINE_C_TOT_OFF - 232 : V12_1_ENGINE_C_TOT_OFF,
2262
- enginePnlPosTotOff: isSbf ? V12_1_ENGINE_PNL_POS_TOT_OFF - 232 : V12_1_ENGINE_PNL_POS_TOT_OFF,
2263
- engineLiqCursorOff: isSbf ? V12_1_ENGINE_LIQ_CURSOR_OFF - 232 : V12_1_ENGINE_LIQ_CURSOR_OFF,
2264
- engineGcCursorOff: isSbf ? V12_1_ENGINE_GC_CURSOR_OFF - 232 : V12_1_ENGINE_GC_CURSOR_OFF,
2265
- engineLastSweepStartOff: isSbf ? V12_1_ENGINE_LAST_SWEEP_START_OFF - 232 : V12_1_ENGINE_LAST_SWEEP_START_OFF,
2266
- engineLastSweepCompleteOff: isSbf ? V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF - 232 : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,
2267
- engineCrankCursorOff: isSbf ? V12_1_ENGINE_CRANK_CURSOR_OFF - 232 : V12_1_ENGINE_CRANK_CURSOR_OFF,
2268
- engineSweepStartIdxOff: isSbf ? V12_1_ENGINE_SWEEP_START_IDX_OFF - 232 : V12_1_ENGINE_SWEEP_START_IDX_OFF,
2269
- engineLifetimeLiquidationsOff: isSbf ? V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF - 232 : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
2270
- engineLifetimeForceClosesOff: isSbf ? V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF - 232 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
2271
- engineNetLpPosOff: isSbf ? V12_1_ENGINE_NET_LP_POS_OFF - 232 : V12_1_ENGINE_NET_LP_POS_OFF,
2272
- engineLpSumAbsOff: isSbf ? V12_1_ENGINE_LP_SUM_ABS_OFF - 232 : V12_1_ENGINE_LP_SUM_ABS_OFF,
2273
- engineLpMaxAbsOff: isSbf ? V12_1_ENGINE_LP_MAX_ABS_OFF - 232 : V12_1_ENGINE_LP_MAX_ABS_OFF,
2274
- engineLpMaxAbsSweepOff: isSbf ? V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF - 232 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF,
2275
- engineEmergencyOiModeOff: isSbf ? V12_1_ENGINE_EMERGENCY_OI_MODE_OFF - 232 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF,
2276
- engineEmergencyStartSlotOff: isSbf ? V12_1_ENGINE_EMERGENCY_START_SLOT_OFF - 232 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF,
2277
- engineLastBreakerSlotOff: isSbf ? V12_1_ENGINE_LAST_BREAKER_SLOT_OFF - 232 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF,
2309
+ paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,
2310
+ // SBF engine offsets all verified by cargo build-sbf offset_of! assertions.
2311
+ // Fields that don't exist in the deployed program are set to -1 on SBF.
2312
+ engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,
2313
+ engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF,
2314
+ // not in deployed struct
2315
+ engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF,
2316
+ // not in deployed struct
2317
+ engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,
2318
+ engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,
2319
+ engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,
2320
+ engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,
2321
+ engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,
2322
+ engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,
2323
+ engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,
2324
+ engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,
2325
+ enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,
2326
+ engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,
2327
+ engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,
2328
+ engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,
2329
+ engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,
2330
+ engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,
2331
+ engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,
2332
+ engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
2333
+ engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
2334
+ // not in deployed struct
2335
+ engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF,
2336
+ // not in deployed struct
2337
+ engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF,
2338
+ // not in deployed struct
2339
+ engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF,
2340
+ // not in deployed struct
2341
+ engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF,
2342
+ // not in deployed struct
2343
+ engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF,
2344
+ // not in deployed struct
2345
+ engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF,
2346
+ // not in deployed struct
2347
+ engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF,
2348
+ // not in deployed struct
2278
2349
  engineBitmapOff: bitmapOff,
2279
2350
  postBitmap: 18,
2280
2351
  acctOwnerOff: V12_1_ACCT_OWNER_OFF,
2281
- hasInsuranceIsolation: true,
2282
- engineInsuranceIsolatedOff: 48,
2283
- engineInsuranceIsolationBpsOff: 64
2352
+ // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.
2353
+ // No isolated_balance or insurance_isolation_bps fields.
2354
+ hasInsuranceIsolation: !isSbf,
2355
+ engineInsuranceIsolatedOff: isSbf ? -1 : 48,
2356
+ engineInsuranceIsolationBpsOff: isSbf ? -1 : 64
2357
+ };
2358
+ }
2359
+ function buildLayoutV12_1EP(maxAccounts) {
2360
+ const engineOff = V12_1_SBF_ENGINE_OFF;
2361
+ const bitmapOff = V12_1_SBF_BITMAP_OFF;
2362
+ const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE;
2363
+ const bitmapWords = Math.ceil(maxAccounts / 64);
2364
+ const bitmapBytes = bitmapWords * 8;
2365
+ const postBitmap = 18;
2366
+ const nextFreeBytes = maxAccounts * 2;
2367
+ const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
2368
+ const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
2369
+ return {
2370
+ version: 1,
2371
+ headerLen: 72,
2372
+ configOffset: 72,
2373
+ configLen: 544,
2374
+ reservedOff: 80,
2375
+ // V1_RESERVED_OFF
2376
+ engineOff,
2377
+ accountSize,
2378
+ maxAccounts,
2379
+ bitmapWords,
2380
+ accountsOff: engineOff + accountsOffRel,
2381
+ engineInsuranceOff: 16,
2382
+ engineParamsOff: 32,
2383
+ // V12_1_ENGINE_PARAMS_OFF_SBF
2384
+ paramsSize: 184,
2385
+ // V12_1_PARAMS_SIZE_SBF
2386
+ // Engine offsets identical to V12_1 SBF
2387
+ engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,
2388
+ engineFundingIndexOff: -1,
2389
+ engineLastFundingSlotOff: -1,
2390
+ engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,
2391
+ engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,
2392
+ engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,
2393
+ engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,
2394
+ engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,
2395
+ engineLongOiOff: V12_1_SBF_OFF_LONG_OI,
2396
+ engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,
2397
+ engineCTotOff: V12_1_SBF_OFF_C_TOT,
2398
+ enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,
2399
+ engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,
2400
+ engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,
2401
+ engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,
2402
+ engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,
2403
+ engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,
2404
+ engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,
2405
+ engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,
2406
+ engineLifetimeForceClosesOff: -1,
2407
+ engineNetLpPosOff: -1,
2408
+ engineLpSumAbsOff: -1,
2409
+ engineLpMaxAbsOff: -1,
2410
+ engineLpMaxAbsSweepOff: -1,
2411
+ engineEmergencyOiModeOff: -1,
2412
+ engineEmergencyStartSlotOff: -1,
2413
+ engineLastBreakerSlotOff: -1,
2414
+ engineBitmapOff: bitmapOff,
2415
+ postBitmap: 18,
2416
+ // Account offsets — shifted +8 from V12_1 due to entry_price insertion
2417
+ acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF,
2418
+ // 216 (was 208)
2419
+ hasInsuranceIsolation: false,
2420
+ engineInsuranceIsolatedOff: -1,
2421
+ engineInsuranceIsolationBpsOff: -1
2284
2422
  };
2285
2423
  }
2286
2424
  function detectSlabLayout(dataLen, data) {
2425
+ const v121epn = V12_1_EP_SIZES.get(dataLen);
2426
+ if (v121epn !== void 0) return buildLayoutV12_1EP(v121epn);
2287
2427
  const v121n = V12_1_SIZES.get(dataLen);
2288
2428
  if (v121n !== void 0) return buildLayoutV12_1(v121n, dataLen);
2289
2429
  const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);
@@ -2330,6 +2470,15 @@ var PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;
2330
2470
  var PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;
2331
2471
  var PARAMS_LIQUIDATION_BUFFER_OFF = 120;
2332
2472
  var PARAMS_MIN_LIQUIDATION_OFF = 128;
2473
+ var V12_1_PARAMS_MAINT_FEE_OFF = 56;
2474
+ var V12_1_PARAMS_MAX_CRANK_OFF = 72;
2475
+ var V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80;
2476
+ var V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88;
2477
+ var V12_1_PARAMS_MIN_LIQ_OFF = 104;
2478
+ var V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120;
2479
+ var V12_1_PARAMS_MIN_NZ_MM_OFF = 136;
2480
+ var V12_1_PARAMS_MIN_NZ_IM_OFF = 152;
2481
+ var V12_1_PARAMS_INS_FLOOR_OFF = 168;
2333
2482
  var ACCT_ACCOUNT_ID_OFF = 0;
2334
2483
  var ACCT_CAPITAL_OFF = 8;
2335
2484
  var ACCT_KIND_OFF = 24;
@@ -2579,6 +2728,7 @@ function parseParams(data, layoutHint) {
2579
2728
  if (data.length < base + Math.min(paramsSize, 56)) {
2580
2729
  throw new Error("Slab data too short for RiskParams");
2581
2730
  }
2731
+ const isV12_1Sbf = layout !== null && layout !== void 0 && layout.engineOff === V12_1_SBF_ENGINE_OFF && paramsSize === 184;
2582
2732
  const result = {
2583
2733
  warmupPeriodSlots: readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),
2584
2734
  maintenanceMarginBps: readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),
@@ -2586,16 +2736,30 @@ function parseParams(data, layoutHint) {
2586
2736
  tradingFeeBps: readU64LE(data, base + PARAMS_TRADING_FEE_OFF),
2587
2737
  maxAccounts: readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),
2588
2738
  newAccountFee: readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),
2589
- // Extended params: only read if V1 (paramsSize >= 144)
2739
+ // Extended params: defaults; overwritten below if layout supports them
2590
2740
  riskReductionThreshold: 0n,
2591
2741
  maintenanceFeePerSlot: 0n,
2592
2742
  maxCrankStalenessSlots: 0n,
2593
2743
  liquidationFeeBps: 0n,
2594
2744
  liquidationFeeCap: 0n,
2595
2745
  liquidationBufferBps: 0n,
2596
- minLiquidationAbs: 0n
2746
+ minLiquidationAbs: 0n,
2747
+ minInitialDeposit: 0n,
2748
+ minNonzeroMmReq: 0n,
2749
+ minNonzeroImReq: 0n,
2750
+ insuranceFloor: 0n
2597
2751
  };
2598
- if (paramsSize >= 144) {
2752
+ if (isV12_1Sbf) {
2753
+ result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);
2754
+ result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);
2755
+ result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);
2756
+ result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);
2757
+ result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);
2758
+ result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);
2759
+ result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);
2760
+ result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);
2761
+ result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);
2762
+ } else if (paramsSize >= 144) {
2599
2763
  result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);
2600
2764
  result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);
2601
2765
  result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);
@@ -2616,17 +2780,18 @@ function parseEngine(data) {
2616
2780
  vault: readU128LE(data, base),
2617
2781
  insuranceFund: {
2618
2782
  balance: readU128LE(data, base + layout.engineInsuranceOff),
2619
- feeRevenue: readU128LE(data, base + layout.engineInsuranceOff + 16),
2783
+ // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)
2784
+ feeRevenue: layout.hasInsuranceIsolation ? readU128LE(data, base + layout.engineInsuranceOff + 16) : 0n,
2620
2785
  isolatedBalance: layout.hasInsuranceIsolation ? readU128LE(data, base + layout.engineInsuranceIsolatedOff) : 0n,
2621
2786
  isolationBps: layout.hasInsuranceIsolation ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff) : 0
2622
2787
  },
2623
2788
  currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),
2624
- fundingIndexQpbE6: readI128LE(data, base + layout.engineFundingIndexOff),
2625
- lastFundingSlot: readU64LE(data, base + layout.engineLastFundingSlotOff),
2789
+ fundingIndexQpbE6: layout.engineFundingIndexOff >= 0 ? readI128LE(data, base + layout.engineFundingIndexOff) : 0n,
2790
+ lastFundingSlot: layout.engineLastFundingSlotOff >= 0 ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,
2626
2791
  fundingRateBpsPerSlotLast: readI64LE(data, base + layout.engineFundingRateBpsOff),
2627
2792
  lastCrankSlot: readU64LE(data, base + layout.engineLastCrankSlotOff),
2628
2793
  maxCrankStalenessSlots: readU64LE(data, base + layout.engineMaxCrankStalenessOff),
2629
- totalOpenInterest: readU128LE(data, base + layout.engineTotalOiOff),
2794
+ totalOpenInterest: layout.engineTotalOiOff >= 0 ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,
2630
2795
  longOi: layout.engineLongOiOff >= 0 ? readU128LE(data, base + layout.engineLongOiOff) : 0n,
2631
2796
  shortOi: layout.engineShortOiOff >= 0 ? readU128LE(data, base + layout.engineShortOiOff) : 0n,
2632
2797
  cTot: readU128LE(data, base + layout.engineCTotOff),
@@ -2638,9 +2803,9 @@ function parseEngine(data) {
2638
2803
  crankCursor: readU16LE(data, base + layout.engineCrankCursorOff),
2639
2804
  sweepStartIdx: readU16LE(data, base + layout.engineSweepStartIdxOff),
2640
2805
  lifetimeLiquidations: readU64LE(data, base + layout.engineLifetimeLiquidationsOff),
2641
- lifetimeForceCloses: readU64LE(data, base + layout.engineLifetimeForceClosesOff),
2642
- netLpPos: readI128LE(data, base + layout.engineNetLpPosOff),
2643
- lpSumAbs: readU128LE(data, base + layout.engineLpSumAbsOff),
2806
+ lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0 ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,
2807
+ netLpPos: layout.engineNetLpPosOff >= 0 ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,
2808
+ lpSumAbs: layout.engineLpSumAbsOff >= 0 ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,
2644
2809
  lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,
2645
2810
  lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,
2646
2811
  emergencyOiMode: layout.engineEmergencyOiModeOff >= 0 ? data[base + layout.engineEmergencyOiModeOff] !== 0 : false,
@@ -2707,17 +2872,18 @@ function parseAccount(data, idx) {
2707
2872
  if (data.length < base + layout.accountSize) {
2708
2873
  throw new Error("Slab data too short for account");
2709
2874
  }
2710
- const isV12_1 = layout.engineOff === V12_1_ENGINE_OFF && (layout.accountSize === V12_1_ACCOUNT_SIZE || layout.accountSize === V12_1_ACCOUNT_SIZE_SBF);
2711
- const isAdl = layout.accountSize >= 312 || isV12_1;
2875
+ const isV12_1EP = layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;
2876
+ const isV12_1 = !isV12_1EP && (layout.engineOff === V12_1_ENGINE_OFF || layout.engineOff === V12_1_SBF_ENGINE_OFF) && (layout.accountSize === V12_1_ACCOUNT_SIZE || layout.accountSize === V12_1_ACCOUNT_SIZE_SBF);
2877
+ const isAdl = layout.accountSize >= 312 || isV12_1 || isV12_1EP;
2712
2878
  const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;
2713
2879
  const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;
2714
- const positionSizeOff = isV12_1 ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
2715
- const entryPriceOff = isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
2716
- const fundingIndexOff = isV12_1 ? V12_1_ACCT_FUNDING_INDEX_OFF : isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
2717
- const matcherProgOff = isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
2718
- const matcherCtxOff = isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
2719
- const feeCreditsOff = isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
2720
- const lastFeeSlotOff = isV12_1 ? V12_1_ACCT_LAST_FEE_SLOT_OFF : isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
2880
+ const positionSizeOff = isV12_1 || isV12_1EP ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
2881
+ const entryPriceOff = isV12_1EP ? V12_1_EP_ACCT_ENTRY_PRICE_OFF : isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
2882
+ const fundingIndexOff = isV12_1 || isV12_1EP ? -1 : isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
2883
+ const matcherProgOff = isV12_1EP ? V12_1_EP_ACCT_MATCHER_PROGRAM_OFF : isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
2884
+ const matcherCtxOff = isV12_1EP ? V12_1_EP_ACCT_MATCHER_CONTEXT_OFF : isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
2885
+ const feeCreditsOff = isV12_1EP ? V12_1_EP_ACCT_FEE_CREDITS_OFF : isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
2886
+ const lastFeeSlotOff = isV12_1EP ? V12_1_EP_ACCT_LAST_FEE_SLOT_OFF : isV12_1 ? V12_1_ACCT_LAST_FEE_SLOT_OFF : isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
2721
2887
  const kindByte = readU8(data, base + ACCT_KIND_OFF);
2722
2888
  const kind = kindByte === 1 ? 1 /* LP */ : 0 /* User */;
2723
2889
  return {
@@ -2730,9 +2896,8 @@ function parseAccount(data, idx) {
2730
2896
  warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),
2731
2897
  positionSize: readI128LE(data, base + positionSizeOff),
2732
2898
  entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,
2733
- // V12_1: entry_price removed
2734
- // V12_1 changed funding_index from i128 to i64 (legacy field moved to end of account)
2735
- fundingIndex: isV12_1 ? BigInt(readI64LE(data, base + fundingIndexOff)) : readI128LE(data, base + fundingIndexOff),
2899
+ // V12_1/V12_1_EP: funding_index not present in SBF layout
2900
+ fundingIndex: isV12_1 || isV12_1EP ? fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n : readI128LE(data, base + fundingIndexOff),
2736
2901
  matcherProgram: new PublicKey3(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),
2737
2902
  matcherContext: new PublicKey3(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),
2738
2903
  owner: new PublicKey3(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),
@@ -2765,6 +2930,12 @@ function deriveVaultAuthority(programId, slab) {
2765
2930
  programId
2766
2931
  );
2767
2932
  }
2933
+ function deriveInsuranceLpMint(programId, slab) {
2934
+ return PublicKey4.findProgramAddressSync(
2935
+ [textEncoder.encode("ins_lp"), slab.toBytes()],
2936
+ programId
2937
+ );
2938
+ }
2768
2939
  var LP_INDEX_U16_MAX = 65535;
2769
2940
  function deriveLpPda(programId, slab, lpIdx) {
2770
2941
  if (typeof lpIdx !== "number" || !Number.isInteger(lpIdx) || lpIdx < 0 || lpIdx > LP_INDEX_U16_MAX) {
@@ -2821,14 +2992,7 @@ function derivePythPushOraclePDA(feedIdHex) {
2821
2992
  }
2822
2993
  const feedId = new Uint8Array(32);
2823
2994
  for (let i = 0; i < 32; i++) {
2824
- const hexPair = normalized.substring(i * 2, i * 2 + 2);
2825
- const byte = parseInt(hexPair, 16);
2826
- if (Number.isNaN(byte)) {
2827
- throw new Error(
2828
- `derivePythPushOraclePDA: failed to parse hex byte at position ${i}: "${hexPair}"`
2829
- );
2830
- }
2831
- feedId[i] = byte;
2995
+ feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);
2832
2996
  }
2833
2997
  const shardBuf = new Uint8Array(2);
2834
2998
  return PublicKey4.findProgramAddressSync(
@@ -2860,9 +3024,7 @@ import { PublicKey as PublicKey6 } from "@solana/web3.js";
2860
3024
  // src/solana/static-markets.ts
2861
3025
  import { PublicKey as PublicKey5 } from "@solana/web3.js";
2862
3026
  var MAINNET_MARKETS = [
2863
- // Populated at mainnet launch currently empty.
2864
- // To add entries:
2865
- // { slabAddress: "ABC123...", symbol: "SOL-PERP", name: "SOL Perpetual" },
3027
+ { slabAddress: "9TGSmPLTLMii4UqstL629twGeVJ9Ndr8VD3pexnvQTsV", symbol: "SOL-PERP", name: "SOL/USDC Perpetual" }
2866
3028
  ];
2867
3029
  var DEVNET_MARKETS = [
2868
3030
  // Populated from prior discoverMarkets() runs on devnet.
@@ -3630,7 +3792,9 @@ function computeRaydiumClmmPriceE6(data) {
3630
3792
  }
3631
3793
  const sqrtPriceX64 = readU128LE3(dv3, 253);
3632
3794
  if (sqrtPriceX64 === 0n) return 0n;
3633
- const priceE6Raw = sqrtPriceX64 * sqrtPriceX64 * 1000000n >> 128n;
3795
+ const scaledSqrt = sqrtPriceX64 * 1000000n;
3796
+ const term = scaledSqrt >> 64n;
3797
+ const priceE6Raw = term * sqrtPriceX64 >> 64n;
3634
3798
  const decimalDiff = 6 + decimals0 - decimals1;
3635
3799
  const adjustedDiff = decimalDiff - 6;
3636
3800
  if (adjustedDiff >= 0) {
@@ -3671,26 +3835,13 @@ function computeMeteoraDlmmPriceE6(data) {
3671
3835
  `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`
3672
3836
  );
3673
3837
  }
3674
- const MAX_ABS_BIN_ID = 5e5;
3675
- if (activeId > MAX_ABS_BIN_ID || activeId < -MAX_ABS_BIN_ID) {
3676
- throw new Error(
3677
- `Meteora DLMM: activeId ${activeId} exceeds safe range (\xB1${MAX_ABS_BIN_ID})`
3678
- );
3679
- }
3680
3838
  const SCALE = 1000000000000000000n;
3681
3839
  const base = SCALE + BigInt(binStep) * SCALE / 10000n;
3682
3840
  const isNeg = activeId < 0;
3683
3841
  let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);
3684
3842
  let result = SCALE;
3685
3843
  let b = base;
3686
- let iterations = 0;
3687
- const MAX_ITERATIONS = 25;
3688
3844
  while (exp > 0n) {
3689
- if (iterations++ >= MAX_ITERATIONS) {
3690
- throw new Error(
3691
- `Meteora DLMM: exponentiation loop exceeded ${MAX_ITERATIONS} iterations (activeId=${activeId})`
3692
- );
3693
- }
3694
3845
  if (exp & 1n) {
3695
3846
  result = result * b / SCALE;
3696
3847
  }
@@ -3721,7 +3872,6 @@ function readU128LE3(dv3, offset) {
3721
3872
  var CHAINLINK_MIN_SIZE = 224;
3722
3873
  var MAX_DECIMALS = 18;
3723
3874
  var CHAINLINK_DECIMALS_OFFSET = 138;
3724
- var CHAINLINK_TIMESTAMP_OFFSET = 168;
3725
3875
  var CHAINLINK_ANSWER_OFFSET = 216;
3726
3876
  function readU82(data, off) {
3727
3877
  return data[off];
@@ -3729,7 +3879,7 @@ function readU82(data, off) {
3729
3879
  function readBigInt64LE(data, off) {
3730
3880
  return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);
3731
3881
  }
3732
- function parseChainlinkPrice(data, options) {
3882
+ function parseChainlinkPrice(data) {
3733
3883
  if (data.length < CHAINLINK_MIN_SIZE) {
3734
3884
  throw new Error(
3735
3885
  `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`
@@ -3747,18 +3897,7 @@ function parseChainlinkPrice(data, options) {
3747
3897
  `Oracle price is non-positive: ${price}`
3748
3898
  );
3749
3899
  }
3750
- const updatedAtBig = readBigInt64LE(data, CHAINLINK_TIMESTAMP_OFFSET);
3751
- const updatedAt = Number(updatedAtBig);
3752
- if (options?.maxStalenessSeconds !== void 0 && updatedAt > 0) {
3753
- const now = Math.floor(Date.now() / 1e3);
3754
- const age = now - updatedAt;
3755
- if (age > options.maxStalenessSeconds) {
3756
- throw new Error(
3757
- `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`
3758
- );
3759
- }
3760
- }
3761
- return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : void 0 };
3900
+ return { price, decimals };
3762
3901
  }
3763
3902
  function isValidChainlinkOracle(data) {
3764
3903
  try {
@@ -3778,11 +3917,7 @@ var TOKEN_2022_PROGRAM_ID = new PublicKey8(
3778
3917
  async function detectTokenProgram(connection, mint) {
3779
3918
  const info = await connection.getAccountInfo(mint);
3780
3919
  if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);
3781
- if (info.owner.equals(TOKEN_PROGRAM_ID3)) return TOKEN_PROGRAM_ID3;
3782
- if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;
3783
- throw new Error(
3784
- `Mint ${mint.toBase58()} is owned by ${info.owner.toBase58()}, which is neither TOKEN_PROGRAM_ID nor TOKEN_2022_PROGRAM_ID`
3785
- );
3920
+ return info.owner;
3786
3921
  }
3787
3922
  function isToken2022(tokenProgramId) {
3788
3923
  return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);
@@ -3815,14 +3950,12 @@ var PROGRAM_IDS = {
3815
3950
  }
3816
3951
  };
3817
3952
  function getProgramId(network) {
3818
- if (!network) {
3819
- const override = safeEnv("PROGRAM_ID");
3820
- if (override) {
3821
- console.warn(
3822
- `[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
3823
- );
3824
- return new PublicKey9(override);
3825
- }
3953
+ const override = safeEnv("PROGRAM_ID");
3954
+ if (override) {
3955
+ console.warn(
3956
+ `[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
3957
+ );
3958
+ return new PublicKey9(override);
3826
3959
  }
3827
3960
  const detectedNetwork = getCurrentNetwork();
3828
3961
  const targetNetwork = network ?? detectedNetwork;
@@ -3830,14 +3963,12 @@ function getProgramId(network) {
3830
3963
  return new PublicKey9(programId);
3831
3964
  }
3832
3965
  function getMatcherProgramId(network) {
3833
- if (!network) {
3834
- const override = safeEnv("MATCHER_PROGRAM_ID");
3835
- if (override) {
3836
- console.warn(
3837
- `[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
3838
- );
3839
- return new PublicKey9(override);
3840
- }
3966
+ const override = safeEnv("MATCHER_PROGRAM_ID");
3967
+ if (override) {
3968
+ console.warn(
3969
+ `[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
3970
+ );
3971
+ return new PublicKey9(override);
3841
3972
  }
3842
3973
  const detectedNetwork = getCurrentNetwork();
3843
3974
  const targetNetwork = network ?? detectedNetwork;
@@ -3870,7 +4001,10 @@ function getStakeProgramId(network) {
3870
4001
  }
3871
4002
  const detectedNetwork = network ?? (() => {
3872
4003
  const n = safeEnv("NEXT_PUBLIC_DEFAULT_NETWORK")?.toLowerCase() ?? safeEnv("NETWORK")?.toLowerCase() ?? "";
3873
- return n === "mainnet" || n === "mainnet-beta" ? "mainnet" : "devnet";
4004
+ if (n === "mainnet" || n === "mainnet-beta") return "mainnet";
4005
+ if (n === "devnet") return "devnet";
4006
+ if (typeof window !== "undefined") return "mainnet";
4007
+ return "devnet";
3874
4008
  })();
3875
4009
  const id = STAKE_PROGRAM_IDS[detectedNetwork];
3876
4010
  if (!id) {
@@ -3880,7 +4014,7 @@ function getStakeProgramId(network) {
3880
4014
  }
3881
4015
  return new PublicKey10(id);
3882
4016
  }
3883
- var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.mainnet);
4017
+ var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.devnet);
3884
4018
  var STAKE_IX = {
3885
4019
  InitPool: 0,
3886
4020
  Deposit: 1,
@@ -3941,9 +4075,6 @@ function readU16LE3(data, off) {
3941
4075
  );
3942
4076
  }
3943
4077
  function u64Le(v) {
3944
- if (typeof v === "number" && !Number.isSafeInteger(v)) {
3945
- throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
3946
- }
3947
4078
  const big = BigInt(v);
3948
4079
  if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);
3949
4080
  if (big > 0xFFFFFFFFFFFFFFFFn) throw new Error(`u64Le: value exceeds u64 max`);
@@ -3952,9 +4083,6 @@ function u64Le(v) {
3952
4083
  return arr;
3953
4084
  }
3954
4085
  function u128Le(v) {
3955
- if (typeof v === "number" && !Number.isSafeInteger(v)) {
3956
- throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
3957
- }
3958
4086
  const big = BigInt(v);
3959
4087
  if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);
3960
4088
  if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);
@@ -3965,7 +4093,7 @@ function u128Le(v) {
3965
4093
  return arr;
3966
4094
  }
3967
4095
  function u16Le(v) {
3968
- if (!Number.isInteger(v) || v < 0 || v > 65535) throw new Error(`u16Le: value must be integer in range 0..65535, got ${v}`);
4096
+ if (v < 0 || v > 65535) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`);
3969
4097
  const arr = new Uint8Array(2);
3970
4098
  new DataView(arr.buffer).setUint16(0, v, true);
3971
4099
  return arr;
@@ -4220,9 +4348,7 @@ function computePnlPct(pnl, capital) {
4220
4348
  }
4221
4349
  function isAdlTriggered(slabData) {
4222
4350
  const layout = detectSlabLayout(slabData.length);
4223
- if (!layout) {
4224
- return false;
4225
- }
4351
+ if (!layout) return false;
4226
4352
  try {
4227
4353
  const engine = parseEngine(slabData);
4228
4354
  if (engine.pnlPosTot === 0n) return false;
@@ -4265,14 +4391,6 @@ function rankAdlPositions(slabData) {
4265
4391
  if (account.kind !== 0 /* User */) continue;
4266
4392
  if (account.positionSize === 0n) continue;
4267
4393
  const side = account.positionSize > 0n ? "long" : "short";
4268
- if (side === "long" && account.positionSize <= 0n) {
4269
- console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=long but positionSize=${account.positionSize}`);
4270
- continue;
4271
- }
4272
- if (side === "short" && account.positionSize >= 0n) {
4273
- console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=short but positionSize=${account.positionSize}`);
4274
- continue;
4275
- }
4276
4394
  const pnlPct = computePnlPct(account.pnl, account.capital);
4277
4395
  positions.push({
4278
4396
  idx,
@@ -4305,8 +4423,7 @@ function buildAdlInstruction(caller, slab, oracle, programId, targetIdx, backupO
4305
4423
  `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`
4306
4424
  );
4307
4425
  }
4308
- const dataBytes = encodeExecuteAdl({ targetIdx });
4309
- const data = Buffer.from(dataBytes);
4426
+ const data = Buffer.from(encodeExecuteAdl({ targetIdx }));
4310
4427
  const keys = [
4311
4428
  { pubkey: caller, isSigner: true, isWritable: false },
4312
4429
  { pubkey: slab, isSigner: false, isWritable: true },
@@ -4346,11 +4463,7 @@ function parseAdlEvent(logs) {
4346
4463
  }
4347
4464
  if (tag !== ADL_EVENT_TAG) continue;
4348
4465
  try {
4349
- const targetIdxBig = BigInt(match[2]);
4350
- if (targetIdxBig < 0n || targetIdxBig > 65535n) {
4351
- continue;
4352
- }
4353
- const targetIdx = Number(targetIdxBig);
4466
+ const targetIdx = Number(BigInt(match[2]));
4354
4467
  const price = BigInt(match[3]);
4355
4468
  const closedLo = BigInt(match[4]);
4356
4469
  const closedHi = BigInt(match[5]);
@@ -4378,387 +4491,9 @@ async function fetchAdlRankings(apiBase, slab, fetchFn = fetch) {
4378
4491
  );
4379
4492
  }
4380
4493
  const json = await res.json();
4381
- if (typeof json !== "object" || json === null) {
4382
- throw new Error("fetchAdlRankings: API returned non-object response");
4383
- }
4384
- const obj = json;
4385
- if (!Array.isArray(obj.rankings)) {
4386
- throw new Error("fetchAdlRankings: API response missing rankings array");
4387
- }
4388
- for (const entry of obj.rankings) {
4389
- if (typeof entry !== "object" || entry === null) {
4390
- throw new Error("fetchAdlRankings: invalid ranking entry (not an object)");
4391
- }
4392
- const r = entry;
4393
- if (typeof r.idx !== "number" || !Number.isInteger(r.idx) || r.idx < 0) {
4394
- throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);
4395
- }
4396
- }
4397
4494
  return json;
4398
4495
  }
4399
4496
 
4400
- // src/solana/rpc-pool.ts
4401
- import {
4402
- Connection as Connection5
4403
- } from "@solana/web3.js";
4404
- async function checkRpcHealth(endpoint, timeoutMs = 5e3) {
4405
- const conn = new Connection5(endpoint, { commitment: "processed" });
4406
- const start = performance.now();
4407
- const timeout = rejectAfter(timeoutMs, `Health probe timed out after ${timeoutMs}ms`);
4408
- try {
4409
- const slot = await Promise.race([
4410
- conn.getSlot("processed"),
4411
- timeout.promise
4412
- ]);
4413
- const latencyMs = Math.round(performance.now() - start);
4414
- return { endpoint, healthy: true, latencyMs, slot };
4415
- } catch (err) {
4416
- const latencyMs = Math.round(performance.now() - start);
4417
- return {
4418
- endpoint,
4419
- healthy: false,
4420
- latencyMs,
4421
- slot: 0,
4422
- error: err instanceof Error ? err.message : String(err)
4423
- };
4424
- } finally {
4425
- timeout.cancel();
4426
- }
4427
- }
4428
- function resolveRetryConfig(cfg) {
4429
- if (cfg === false) return null;
4430
- const c = cfg ?? {};
4431
- return {
4432
- maxRetries: c.maxRetries ?? 3,
4433
- baseDelayMs: c.baseDelayMs ?? 500,
4434
- maxDelayMs: c.maxDelayMs ?? 1e4,
4435
- jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),
4436
- retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504]
4437
- };
4438
- }
4439
- function normalizeEndpoint(ep) {
4440
- if (typeof ep === "string") return { url: ep };
4441
- return ep;
4442
- }
4443
- function endpointLabel(ep) {
4444
- if (ep.label) return ep.label;
4445
- try {
4446
- return new URL(ep.url).hostname;
4447
- } catch {
4448
- return ep.url.slice(0, 40);
4449
- }
4450
- }
4451
- function isRetryable(err, codes) {
4452
- if (!err) return false;
4453
- const msg = err instanceof Error ? err.message : String(err);
4454
- for (const code of codes) {
4455
- if (msg.includes(String(code))) return true;
4456
- }
4457
- if (msg.toLowerCase().includes("rate limit") || msg.toLowerCase().includes("too many requests") || msg.toLowerCase().includes("econnreset") || msg.toLowerCase().includes("econnrefused") || msg.toLowerCase().includes("socket hang up") || msg.toLowerCase().includes("network") || msg.toLowerCase().includes("timeout") || msg.toLowerCase().includes("abort")) {
4458
- return true;
4459
- }
4460
- return false;
4461
- }
4462
- function computeDelay(attempt, config) {
4463
- const raw = Math.min(
4464
- config.baseDelayMs * Math.pow(2, attempt),
4465
- config.maxDelayMs
4466
- );
4467
- const jitter = Math.floor(Math.random() * raw * config.jitterFactor);
4468
- return raw + jitter;
4469
- }
4470
- function rejectAfter(ms, message) {
4471
- let timer;
4472
- const promise = new Promise((_, reject) => {
4473
- timer = setTimeout(() => reject(new Error(message)), ms);
4474
- });
4475
- return { promise, cancel: () => clearTimeout(timer) };
4476
- }
4477
- function sleep(ms) {
4478
- return new Promise((resolve) => setTimeout(resolve, ms));
4479
- }
4480
- function redactUrl(raw) {
4481
- try {
4482
- const u = new URL(raw);
4483
- const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;
4484
- for (const k of [...u.searchParams.keys()]) {
4485
- if (sensitive.test(k)) {
4486
- u.searchParams.set(k, "***");
4487
- }
4488
- }
4489
- return u.toString();
4490
- } catch {
4491
- return raw;
4492
- }
4493
- }
4494
- var RpcPool = class _RpcPool {
4495
- endpoints;
4496
- strategy;
4497
- retryConfig;
4498
- requestTimeoutMs;
4499
- verbose;
4500
- /** Round-robin index tracker. */
4501
- rrIndex = 0;
4502
- /** Consecutive failure threshold before marking an endpoint unhealthy. */
4503
- static UNHEALTHY_THRESHOLD = 3;
4504
- /** Minimum endpoints before auto-recovery is attempted. */
4505
- static MIN_HEALTHY = 1;
4506
- constructor(config) {
4507
- if (!config.endpoints || config.endpoints.length === 0) {
4508
- throw new Error("RpcPool: at least one endpoint is required");
4509
- }
4510
- this.strategy = config.strategy ?? "failover";
4511
- this.retryConfig = resolveRetryConfig(config.retry);
4512
- this.requestTimeoutMs = config.requestTimeoutMs ?? 3e4;
4513
- this.verbose = config.verbose ?? true;
4514
- const commitment = config.commitment ?? "confirmed";
4515
- this.endpoints = config.endpoints.map((raw) => {
4516
- const ep = normalizeEndpoint(raw);
4517
- const connConfig = {
4518
- commitment,
4519
- ...ep.connectionConfig
4520
- };
4521
- return {
4522
- config: ep,
4523
- connection: new Connection5(ep.url, connConfig),
4524
- label: endpointLabel(ep),
4525
- weight: Math.max(1, ep.weight ?? 1),
4526
- failures: 0,
4527
- healthy: true,
4528
- lastLatencyMs: -1
4529
- };
4530
- });
4531
- }
4532
- // -----------------------------------------------------------------------
4533
- // Public API
4534
- // -----------------------------------------------------------------------
4535
- /**
4536
- * Execute a function against a pooled connection with automatic retry
4537
- * and failover.
4538
- *
4539
- * @param fn - Async function that receives a `Connection` and returns a result.
4540
- * @returns The result of `fn`.
4541
- * @throws The last error if all retries and failovers are exhausted.
4542
- *
4543
- * @example
4544
- * ```ts
4545
- * const balance = await pool.call(c => c.getBalance(pubkey));
4546
- * const markets = await pool.call(c => discoverMarkets(c, programId, opts));
4547
- * ```
4548
- */
4549
- async call(fn) {
4550
- const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;
4551
- let lastError;
4552
- const triedEndpoints = /* @__PURE__ */ new Set();
4553
- const maxTotalIterations = maxAttempts + this.endpoints.length;
4554
- let totalIterations = 0;
4555
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
4556
- if (++totalIterations > maxTotalIterations) break;
4557
- const epIdx = this.selectEndpoint(triedEndpoints);
4558
- if (epIdx === -1) {
4559
- break;
4560
- }
4561
- const ep = this.endpoints[epIdx];
4562
- const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);
4563
- try {
4564
- const result = await Promise.race([
4565
- fn(ep.connection),
4566
- timeout.promise
4567
- ]);
4568
- timeout.cancel();
4569
- ep.failures = 0;
4570
- ep.healthy = true;
4571
- return result;
4572
- } catch (err) {
4573
- timeout.cancel();
4574
- lastError = err;
4575
- ep.failures++;
4576
- if (ep.failures >= _RpcPool.UNHEALTHY_THRESHOLD) {
4577
- ep.healthy = false;
4578
- if (this.verbose) {
4579
- console.warn(
4580
- `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`
4581
- );
4582
- }
4583
- }
4584
- const retryable = this.retryConfig ? isRetryable(err, this.retryConfig.retryableStatusCodes) : false;
4585
- if (!retryable) {
4586
- if (this.strategy === "failover" && this.endpoints.length > 1) {
4587
- triedEndpoints.add(epIdx);
4588
- attempt--;
4589
- if (triedEndpoints.size >= this.endpoints.length) break;
4590
- continue;
4591
- }
4592
- throw err;
4593
- }
4594
- if (this.verbose) {
4595
- console.warn(
4596
- `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,
4597
- err instanceof Error ? err.message : err
4598
- );
4599
- }
4600
- if (this.strategy === "failover" && this.endpoints.length > 1) {
4601
- triedEndpoints.add(epIdx);
4602
- }
4603
- if (attempt < maxAttempts - 1 && this.retryConfig) {
4604
- const delay = computeDelay(attempt, this.retryConfig);
4605
- await sleep(delay);
4606
- }
4607
- }
4608
- }
4609
- this.maybeRecoverEndpoints();
4610
- throw lastError ?? new Error("RpcPool: all endpoints exhausted");
4611
- }
4612
- /**
4613
- * Get a raw `Connection` from the current preferred endpoint.
4614
- * Useful when you need to pass a Connection to external code.
4615
- *
4616
- * NOTE: This bypasses retry and failover logic. Prefer `call()`.
4617
- *
4618
- * @returns Solana Connection from the current preferred endpoint.
4619
- *
4620
- * @example
4621
- * ```ts
4622
- * const conn = pool.getConnection();
4623
- * const balance = await conn.getBalance(pubkey);
4624
- * ```
4625
- */
4626
- getConnection() {
4627
- const idx = this.selectEndpoint();
4628
- if (idx === -1) {
4629
- this.maybeRecoverEndpoints();
4630
- return this.endpoints[0].connection;
4631
- }
4632
- return this.endpoints[idx].connection;
4633
- }
4634
- /**
4635
- * Run a health check against all endpoints in the pool.
4636
- *
4637
- * @param timeoutMs - Per-endpoint probe timeout (default: 5000)
4638
- * @returns Array of health results, one per endpoint.
4639
- *
4640
- * @example
4641
- * ```ts
4642
- * const results = await pool.healthCheck();
4643
- * for (const r of results) {
4644
- * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);
4645
- * }
4646
- * ```
4647
- */
4648
- async healthCheck(timeoutMs = 5e3) {
4649
- const results = await Promise.all(
4650
- this.endpoints.map(async (ep) => {
4651
- const result = await checkRpcHealth(ep.config.url, timeoutMs);
4652
- ep.lastLatencyMs = result.latencyMs;
4653
- ep.healthy = result.healthy;
4654
- if (result.healthy) ep.failures = 0;
4655
- result.endpoint = redactUrl(result.endpoint);
4656
- return result;
4657
- })
4658
- );
4659
- return results;
4660
- }
4661
- /**
4662
- * Get the number of endpoints in the pool.
4663
- */
4664
- get size() {
4665
- return this.endpoints.length;
4666
- }
4667
- /**
4668
- * Get the number of currently healthy endpoints.
4669
- */
4670
- get healthyCount() {
4671
- return this.endpoints.filter((ep) => ep.healthy).length;
4672
- }
4673
- /**
4674
- * Get endpoint labels and their current status.
4675
- *
4676
- * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.
4677
- */
4678
- status() {
4679
- return this.endpoints.map((ep) => ({
4680
- label: ep.label,
4681
- url: redactUrl(ep.config.url),
4682
- healthy: ep.healthy,
4683
- failures: ep.failures,
4684
- lastLatencyMs: ep.lastLatencyMs
4685
- }));
4686
- }
4687
- // -----------------------------------------------------------------------
4688
- // Internals
4689
- // -----------------------------------------------------------------------
4690
- /**
4691
- * Select the next endpoint based on strategy.
4692
- * Returns -1 if no endpoint is available.
4693
- */
4694
- selectEndpoint(exclude) {
4695
- const healthy = this.endpoints.map((ep, i) => ({ ep, i })).filter(({ ep, i }) => ep.healthy && !exclude?.has(i));
4696
- if (healthy.length === 0) {
4697
- const remaining = this.endpoints.map((_, i) => i).filter((i) => !exclude?.has(i));
4698
- return remaining.length > 0 ? remaining[0] : -1;
4699
- }
4700
- if (this.strategy === "failover") {
4701
- return healthy[0].i;
4702
- }
4703
- const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);
4704
- this.rrIndex = (this.rrIndex + 1) % totalWeight;
4705
- let cumulative = 0;
4706
- for (const { ep, i } of healthy) {
4707
- cumulative += ep.weight;
4708
- if (this.rrIndex < cumulative) return i;
4709
- }
4710
- return healthy[healthy.length - 1].i;
4711
- }
4712
- /**
4713
- * If all endpoints are unhealthy, reset them so we at least try again.
4714
- */
4715
- maybeRecoverEndpoints() {
4716
- const healthyCount = this.endpoints.filter((ep) => ep.healthy).length;
4717
- if (healthyCount < _RpcPool.MIN_HEALTHY) {
4718
- if (this.verbose) {
4719
- console.warn("[RpcPool] All endpoints unhealthy \u2014 resetting for recovery");
4720
- }
4721
- for (const ep of this.endpoints) {
4722
- ep.healthy = true;
4723
- ep.failures = 0;
4724
- }
4725
- }
4726
- }
4727
- };
4728
- async function withRetry(fn, config) {
4729
- const resolved = resolveRetryConfig(config) ?? {
4730
- maxRetries: 3,
4731
- baseDelayMs: 500,
4732
- maxDelayMs: 1e4,
4733
- jitterFactor: 0.25,
4734
- retryableStatusCodes: [429, 502, 503, 504]
4735
- };
4736
- let lastError;
4737
- const maxAttempts = resolved.maxRetries + 1;
4738
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
4739
- try {
4740
- return await fn();
4741
- } catch (err) {
4742
- lastError = err;
4743
- if (!isRetryable(err, resolved.retryableStatusCodes)) {
4744
- throw err;
4745
- }
4746
- if (attempt < maxAttempts - 1) {
4747
- const delay = computeDelay(attempt, resolved);
4748
- await sleep(delay);
4749
- }
4750
- }
4751
- }
4752
- throw lastError ?? new Error("withRetry: all attempts exhausted");
4753
- }
4754
- var _internal = {
4755
- isRetryable,
4756
- computeDelay,
4757
- resolveRetryConfig,
4758
- normalizeEndpoint,
4759
- endpointLabel
4760
- };
4761
-
4762
4497
  // src/runtime/tx.ts
4763
4498
  import {
4764
4499
  TransactionInstruction as TransactionInstruction2,
@@ -4910,139 +4645,6 @@ function formatResult(result, jsonMode) {
4910
4645
  return lines.join("\n");
4911
4646
  }
4912
4647
 
4913
- // src/runtime/lighthouse.ts
4914
- import { PublicKey as PublicKey13, Transaction as Transaction2 } from "@solana/web3.js";
4915
- var LIGHTHOUSE_PROGRAM_ID = new PublicKey13(
4916
- "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"
4917
- );
4918
- var LIGHTHOUSE_PROGRAM_ID_STR2 = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
4919
- var LIGHTHOUSE_CONSTRAINT_ADDRESS = 6400;
4920
- var LIGHTHOUSE_ERROR_CODES = /* @__PURE__ */ new Set([
4921
- 6e3,
4922
- // InstructionMissing
4923
- 6001,
4924
- // InstructionFallbackNotFound
4925
- 6002,
4926
- // InstructionDidNotDeserialize
4927
- 6003,
4928
- // InstructionDidNotSerialize
4929
- 6016,
4930
- // IdlInstructionStub
4931
- 6032,
4932
- // ConstraintMut
4933
- 6033,
4934
- // ConstraintHasOne
4935
- 6034,
4936
- // ConstraintSigner
4937
- 6035,
4938
- // ConstraintRaw
4939
- 6036,
4940
- // ConstraintOwner
4941
- 6037,
4942
- // ConstraintRentExempt
4943
- 6038,
4944
- // ConstraintSeeds
4945
- 6039,
4946
- // ConstraintExecutable
4947
- 6040,
4948
- // ConstraintState
4949
- 6041,
4950
- // ConstraintAssociated
4951
- 6042,
4952
- // ConstraintAssociatedInit
4953
- 6043,
4954
- // ConstraintClose
4955
- 6400
4956
- // ConstraintAddress (the one we hit most often)
4957
- ]);
4958
- function isLighthouseInstruction(ix) {
4959
- return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);
4960
- }
4961
- function isLighthouseError(error) {
4962
- const msg = extractErrorMessage(error);
4963
- if (!msg) return false;
4964
- if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR2)) return true;
4965
- if (/custom\s+program\s+error:\s*0x1900\b/i.test(msg)) return true;
4966
- if (/"Custom"\s*:\s*6400\b/.test(msg) && /InstructionError/i.test(msg)) return true;
4967
- return false;
4968
- }
4969
- function isLighthouseFailureInLogs(logs) {
4970
- if (!Array.isArray(logs)) return false;
4971
- let insideLighthouse = false;
4972
- for (const line of logs) {
4973
- if (typeof line !== "string") continue;
4974
- if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} invoke`)) {
4975
- insideLighthouse = true;
4976
- continue;
4977
- }
4978
- if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} success`)) {
4979
- insideLighthouse = false;
4980
- continue;
4981
- }
4982
- if (insideLighthouse && /failed/i.test(line)) {
4983
- return true;
4984
- }
4985
- if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} failed`)) {
4986
- return true;
4987
- }
4988
- }
4989
- return false;
4990
- }
4991
- function stripLighthouseInstructions(instructions, percolatorProgramId) {
4992
- if (percolatorProgramId) {
4993
- const hasPercolatorIx = instructions.some(
4994
- (ix) => ix.programId.equals(percolatorProgramId)
4995
- );
4996
- if (!hasPercolatorIx) {
4997
- return instructions;
4998
- }
4999
- }
5000
- return instructions.filter((ix) => !isLighthouseInstruction(ix));
5001
- }
5002
- function stripLighthouseFromTransaction(transaction, percolatorProgramId) {
5003
- if (percolatorProgramId) {
5004
- const hasPercolatorIx = transaction.instructions.some(
5005
- (ix) => ix.programId.equals(percolatorProgramId)
5006
- );
5007
- if (!hasPercolatorIx) return transaction;
5008
- }
5009
- const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);
5010
- if (!hasLighthouse) return transaction;
5011
- const clean = new Transaction2();
5012
- clean.recentBlockhash = transaction.recentBlockhash;
5013
- clean.feePayer = transaction.feePayer;
5014
- for (const ix of transaction.instructions) {
5015
- if (!isLighthouseInstruction(ix)) {
5016
- clean.add(ix);
5017
- }
5018
- }
5019
- return clean;
5020
- }
5021
- function countLighthouseInstructions(ixsOrTx) {
5022
- const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;
5023
- return instructions.filter(isLighthouseInstruction).length;
5024
- }
5025
- var LIGHTHOUSE_USER_MESSAGE = "Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. This is a known compatibility issue \u2014 the transaction itself is valid. Try one of these workarounds:\n1. Disable transaction simulation in your wallet settings\n2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\n3. The SDK will automatically retry without the guard";
5026
- function classifyLighthouseError(error) {
5027
- if (isLighthouseError(error)) {
5028
- return LIGHTHOUSE_USER_MESSAGE;
5029
- }
5030
- return null;
5031
- }
5032
- function extractErrorMessage(error) {
5033
- if (!error) return null;
5034
- if (typeof error === "string") return error;
5035
- if (error instanceof Error) return error.message;
5036
- if (typeof error === "object" && "message" in error) {
5037
- return String(error.message);
5038
- }
5039
- try {
5040
- return JSON.stringify(error);
5041
- } catch {
5042
- return null;
5043
- }
5044
- }
5045
-
5046
4648
  // src/math/trading.ts
5047
4649
  function computeMarkPnl(positionSize, entryPrice, oraclePrice) {
5048
4650
  if (positionSize === 0n || oraclePrice === 0n) return 0n;
@@ -5067,10 +4669,16 @@ function computeLiqPrice(entryPrice, capital, positionSize, maintenanceMarginBps
5067
4669
  function computePreTradeLiqPrice(oracleE6, margin, posSize, maintBps, feeBps, direction) {
5068
4670
  if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;
5069
4671
  const absPos = posSize < 0n ? -posSize : posSize;
5070
- const fee = absPos * feeBps / 10000n;
5071
- const effectiveCapital = margin > fee ? margin - fee : 0n;
5072
4672
  const signedPos = direction === "long" ? absPos : -absPos;
5073
- return computeLiqPrice(oracleE6, effectiveCapital, signedPos, maintBps);
4673
+ const feeAdjust = oracleE6 * feeBps / 10000n;
4674
+ let adjustedEntry;
4675
+ if (direction === "long") {
4676
+ adjustedEntry = oracleE6 + feeAdjust;
4677
+ } else {
4678
+ const shortEntry = oracleE6 - feeAdjust;
4679
+ adjustedEntry = shortEntry > 0n ? shortEntry : 1n;
4680
+ }
4681
+ return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);
5074
4682
  }
5075
4683
  function computeTradingFee(notional, tradingFeeBps) {
5076
4684
  return notional * tradingFeeBps / 10000n;
@@ -5090,20 +4698,9 @@ function computeFeeSplit(totalFee, config) {
5090
4698
  if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {
5091
4699
  return [totalFee, 0n, 0n];
5092
4700
  }
5093
- const totalBps = config.lpBps + config.protocolBps + config.creatorBps;
5094
- if (totalBps !== 10000n) {
5095
- throw new Error(
5096
- `Fee split must equal exactly 10000 bps (100%): lpBps=${config.lpBps} + protocolBps=${config.protocolBps} + creatorBps=${config.creatorBps} = ${totalBps}`
5097
- );
5098
- }
5099
4701
  const lp = totalFee * config.lpBps / 10000n;
5100
4702
  const protocol = totalFee * config.protocolBps / 10000n;
5101
4703
  const creator = totalFee - lp - protocol;
5102
- if (creator < 0n) {
5103
- throw new Error(
5104
- `Internal error: creator fee is negative (${creator}). This should not happen if lpBps + protocolBps + creatorBps === 10000.`
5105
- );
5106
- }
5107
4704
  return [lp, protocol, creator];
5108
4705
  }
5109
4706
  function computePnlPercent(pnlTokens, capital) {
@@ -5118,17 +4715,10 @@ function computePnlPercent(pnlTokens, capital) {
5118
4715
  }
5119
4716
  function computeEstimatedEntryPrice(oracleE6, tradingFeeBps, direction) {
5120
4717
  if (oracleE6 === 0n) return 0n;
5121
- if (tradingFeeBps < 0n) {
5122
- throw new Error(`computeEstimatedEntryPrice: tradingFeeBps must be non-negative, got ${tradingFeeBps}`);
5123
- }
5124
4718
  const feeImpact = oracleE6 * tradingFeeBps / 10000n;
5125
- const result = direction === "long" ? oracleE6 + feeImpact : oracleE6 - feeImpact;
5126
- if (result <= 0n) {
5127
- throw new Error(
5128
- `computeEstimatedEntryPrice: result ${result} is non-positive (tradingFeeBps=${tradingFeeBps} too high for oracle=${oracleE6})`
5129
- );
5130
- }
5131
- return result;
4719
+ if (direction === "long") return oracleE6 + feeImpact;
4720
+ const shortEntry = oracleE6 - feeImpact;
4721
+ return shortEntry > 0n ? shortEntry : 1n;
5132
4722
  }
5133
4723
  var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
5134
4724
  var MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);
@@ -5149,12 +4739,7 @@ function computeMaxLeverage(initialMarginBps) {
5149
4739
  if (initialMarginBps <= 0n) {
5150
4740
  throw new Error("computeMaxLeverage: initialMarginBps must be positive");
5151
4741
  }
5152
- const scaledResult = 10000n * 1000000n / initialMarginBps;
5153
- return Number(scaledResult) / 1e6;
5154
- }
5155
- function computeMaxWithdrawable(capital, pnl, reservedPnl) {
5156
- const maturedPnl = pnl - reservedPnl;
5157
- return capital + (maturedPnl > 0n ? maturedPnl : 0n);
4742
+ return Number(10000n / initialMarginBps);
5158
4743
  }
5159
4744
 
5160
4745
  // src/math/warmup.ts
@@ -5166,9 +4751,6 @@ function computeWarmupUnlockedCapital(totalCapital, currentSlot, warmupStartSlot
5166
4751
  return totalCapital * elapsed / warmupPeriodSlots;
5167
4752
  }
5168
4753
  function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
5169
- if (initialMarginBps <= 0n) {
5170
- throw new Error("computeWarmupLeverageCap: initialMarginBps must be positive");
5171
- }
5172
4754
  const maxLev = computeMaxLeverage(initialMarginBps);
5173
4755
  if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return maxLev;
5174
4756
  if (totalCapital <= 0n) return 1;
@@ -5179,14 +4761,7 @@ function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, w
5179
4761
  warmupPeriodSlots
5180
4762
  );
5181
4763
  if (unlocked <= 0n) return 1;
5182
- const scaledResult = BigInt(maxLev) * unlocked / totalCapital;
5183
- if (scaledResult > BigInt(Number.MAX_SAFE_INTEGER)) {
5184
- console.warn(
5185
- `[computeWarmupLeverageCap] Warning: effective leverage ${scaledResult} exceeds MAX_SAFE_INTEGER, returning MAX_SAFE_INTEGER as a safety bound`
5186
- );
5187
- return Number.MAX_SAFE_INTEGER;
5188
- }
5189
- const effectiveLev = Number(scaledResult);
4764
+ const effectiveLev = Number(BigInt(maxLev) * unlocked / totalCapital);
5190
4765
  return Math.max(1, effectiveLev);
5191
4766
  }
5192
4767
  function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
@@ -5199,41 +4774,10 @@ function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlo
5199
4774
  );
5200
4775
  return unlocked * BigInt(maxLev);
5201
4776
  }
5202
- function computeWarmupProgress(currentSlot, warmupStartedAtSlot, warmupPeriodSlots, pnl, reservedPnl) {
5203
- if (warmupPeriodSlots === 0n || warmupStartedAtSlot === 0n) {
5204
- return {
5205
- maturedPnl: pnl > 0n ? pnl : 0n,
5206
- reservedPnl: 0n,
5207
- progressBps: 10000n,
5208
- // 100%
5209
- slotsRemaining: 0n
5210
- };
5211
- }
5212
- const elapsed = currentSlot >= warmupStartedAtSlot ? currentSlot - warmupStartedAtSlot : 0n;
5213
- if (elapsed >= warmupPeriodSlots) {
5214
- return {
5215
- maturedPnl: pnl > 0n ? pnl : 0n,
5216
- reservedPnl: 0n,
5217
- progressBps: 10000n,
5218
- // 100%
5219
- slotsRemaining: 0n
5220
- };
5221
- }
5222
- const progressBps = elapsed * 10000n / warmupPeriodSlots;
5223
- const slotsRemaining = warmupPeriodSlots - elapsed;
5224
- const maturedPnl = pnl > 0n ? pnl * progressBps / 10000n : 0n;
5225
- const locked = reservedPnl > 0n ? reservedPnl : 0n;
5226
- return {
5227
- maturedPnl,
5228
- reservedPnl: locked,
5229
- progressBps,
5230
- slotsRemaining
5231
- };
5232
- }
5233
4777
 
5234
4778
  // src/validation.ts
5235
- import { PublicKey as PublicKey14 } from "@solana/web3.js";
5236
- var U16_MAX = 65535;
4779
+ import { PublicKey as PublicKey13 } from "@solana/web3.js";
4780
+ var U16_MAX2 = 65535;
5237
4781
  var U64_MAX = BigInt("18446744073709551615");
5238
4782
  var I64_MIN = BigInt("-9223372036854775808");
5239
4783
  var I64_MAX = BigInt("9223372036854775807");
@@ -5262,7 +4806,7 @@ var ValidationError = class extends Error {
5262
4806
  };
5263
4807
  function validatePublicKey(value, field) {
5264
4808
  try {
5265
- return new PublicKey14(value);
4809
+ return new PublicKey13(value);
5266
4810
  } catch {
5267
4811
  throw new ValidationError(
5268
4812
  field,
@@ -5273,26 +4817,24 @@ function validatePublicKey(value, field) {
5273
4817
  function validateIndex(value, field) {
5274
4818
  const t = requireDecimalUIntString(value, field);
5275
4819
  const bi = BigInt(t);
5276
- if (bi > BigInt(U16_MAX)) {
4820
+ if (bi > BigInt(U16_MAX2)) {
5277
4821
  throw new ValidationError(
5278
4822
  field,
5279
- `must be <= ${U16_MAX} (u16 max), got ${t}`
4823
+ `must be <= ${U16_MAX2} (u16 max), got ${t}`
5280
4824
  );
5281
4825
  }
5282
- if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
5283
- throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
5284
- }
5285
4826
  return Number(bi);
5286
4827
  }
5287
4828
  function validateAmount(value, field) {
5288
- const t = value.trim();
5289
- if (!/^(0|[1-9]\d*)$/.test(t)) {
4829
+ let num;
4830
+ try {
4831
+ num = BigInt(value);
4832
+ } catch {
5290
4833
  throw new ValidationError(
5291
4834
  field,
5292
- `"${value}" is not a valid non-negative integer. Use decimal digits only.`
4835
+ `"${value}" is not a valid number. Use decimal digits only.`
5293
4836
  );
5294
4837
  }
5295
- const num = BigInt(t);
5296
4838
  if (num < 0n) {
5297
4839
  throw new ValidationError(field, `must be non-negative, got ${num}`);
5298
4840
  }
@@ -5305,14 +4847,15 @@ function validateAmount(value, field) {
5305
4847
  return num;
5306
4848
  }
5307
4849
  function validateU128(value, field) {
5308
- const t = value.trim();
5309
- if (!/^(0|[1-9]\d*)$/.test(t)) {
4850
+ let num;
4851
+ try {
4852
+ num = BigInt(value);
4853
+ } catch {
5310
4854
  throw new ValidationError(
5311
4855
  field,
5312
- `"${value}" is not a valid non-negative integer. Use decimal digits only.`
4856
+ `"${value}" is not a valid number. Use decimal digits only.`
5313
4857
  );
5314
4858
  }
5315
- const num = BigInt(t);
5316
4859
  if (num < 0n) {
5317
4860
  throw new ValidationError(field, `must be non-negative, got ${num}`);
5318
4861
  }
@@ -5325,14 +4868,15 @@ function validateU128(value, field) {
5325
4868
  return num;
5326
4869
  }
5327
4870
  function validateI64(value, field) {
5328
- const t = value.trim();
5329
- if (!/^-?(0|[1-9]\d*)$/.test(t)) {
4871
+ let num;
4872
+ try {
4873
+ num = BigInt(value);
4874
+ } catch {
5330
4875
  throw new ValidationError(
5331
4876
  field,
5332
- `"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
4877
+ `"${value}" is not a valid number. Use decimal digits only, with optional leading minus.`
5333
4878
  );
5334
4879
  }
5335
- const num = BigInt(t);
5336
4880
  if (num < I64_MIN) {
5337
4881
  throw new ValidationError(
5338
4882
  field,
@@ -5348,14 +4892,15 @@ function validateI64(value, field) {
5348
4892
  return num;
5349
4893
  }
5350
4894
  function validateI128(value, field) {
5351
- const t = value.trim();
5352
- if (!/^-?(0|[1-9]\d*)$/.test(t)) {
4895
+ let num;
4896
+ try {
4897
+ num = BigInt(value);
4898
+ } catch {
5353
4899
  throw new ValidationError(
5354
4900
  field,
5355
- `"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
4901
+ `"${value}" is not a valid number. Use decimal digits only, with optional leading minus.`
5356
4902
  );
5357
4903
  }
5358
- const num = BigInt(t);
5359
4904
  if (num < I128_MIN) {
5360
4905
  throw new ValidationError(
5361
4906
  field,
@@ -5379,9 +4924,6 @@ function validateBps(value, field) {
5379
4924
  `must be <= 10000 (100%), got ${t}`
5380
4925
  );
5381
4926
  }
5382
- if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
5383
- throw new ValidationError(field, `internal error: bps value exceeds MAX_SAFE_INTEGER`);
5384
- }
5385
4927
  return Number(bi);
5386
4928
  }
5387
4929
  function validateU64(value, field) {
@@ -5390,15 +4932,12 @@ function validateU64(value, field) {
5390
4932
  function validateU16(value, field) {
5391
4933
  const t = requireDecimalUIntString(value, field);
5392
4934
  const bi = BigInt(t);
5393
- if (bi > BigInt(U16_MAX)) {
4935
+ if (bi > BigInt(U16_MAX2)) {
5394
4936
  throw new ValidationError(
5395
4937
  field,
5396
- `must be <= ${U16_MAX} (u16 max), got ${t}`
4938
+ `must be <= ${U16_MAX2} (u16 max), got ${t}`
5397
4939
  );
5398
4940
  }
5399
- if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
5400
- throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
5401
- }
5402
4941
  return Number(bi);
5403
4942
  }
5404
4943
 
@@ -5449,9 +4988,7 @@ function parseDexScreenerPairs(json) {
5449
4988
  else if (liquidity > 1e4) confidence = 60;
5450
4989
  else if (liquidity > 1e3) confidence = 45;
5451
4990
  const priceUsd = pair.priceUsd;
5452
- const rawPrice = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) : NaN;
5453
- if (!Number.isFinite(rawPrice) || rawPrice <= 0) continue;
5454
- const price = rawPrice;
4991
+ const price = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) || 0 : 0;
5455
4992
  let baseSym = "?";
5456
4993
  let quoteSym = "?";
5457
4994
  if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === "string") {
@@ -5482,8 +5019,8 @@ function parseJupiterMintEntry(json, mint) {
5482
5019
  if (!isRecord(row)) return null;
5483
5020
  const rawPrice = row.price;
5484
5021
  if (rawPrice === void 0 || rawPrice === null) return null;
5485
- const price = parseFloat(String(rawPrice));
5486
- if (!Number.isFinite(price) || price <= 0) return null;
5022
+ const price = parseFloat(String(rawPrice)) || 0;
5023
+ if (price <= 0) return null;
5487
5024
  let mintSymbol = "?";
5488
5025
  if (typeof row.mintSymbol === "string") mintSymbol = row.mintSymbol;
5489
5026
  return { price, mintSymbol };
@@ -5549,17 +5086,10 @@ async function fetchDexSources(mint, signal) {
5549
5086
  headers: { "User-Agent": "percolator/1.0" }
5550
5087
  }
5551
5088
  );
5552
- if (!resp.ok) {
5553
- console.debug(`[fetchDexSources] HTTP ${resp.status} for mint ${mint}`);
5554
- return [];
5555
- }
5089
+ if (!resp.ok) return [];
5556
5090
  const json = await resp.json();
5557
5091
  return parseDexScreenerPairs(json);
5558
- } catch (err) {
5559
- console.warn(
5560
- `[fetchDexSources] Error fetching DexScreener data for mint ${mint}:`,
5561
- err instanceof Error ? err.message : String(err)
5562
- );
5092
+ } catch {
5563
5093
  return [];
5564
5094
  }
5565
5095
  }
@@ -5570,7 +5100,7 @@ function lookupPythSource(mint) {
5570
5100
  type: "pyth",
5571
5101
  address: entry.feedId,
5572
5102
  pairLabel: `${entry.symbol} / USD (Pyth)`,
5573
- liquidity: Number.MAX_SAFE_INTEGER,
5103
+ liquidity: Infinity,
5574
5104
  // Pyth is considered deep liquidity
5575
5105
  price: 0,
5576
5106
  // We don't fetch live price here; caller can enrich
@@ -5587,16 +5117,10 @@ async function fetchJupiterSource(mint, signal) {
5587
5117
  headers: { "User-Agent": "percolator/1.0" }
5588
5118
  }
5589
5119
  );
5590
- if (!resp.ok) {
5591
- console.debug(`[fetchJupiterSource] HTTP ${resp.status} for mint ${mint}`);
5592
- return null;
5593
- }
5120
+ if (!resp.ok) return null;
5594
5121
  const json = await resp.json();
5595
5122
  const row = parseJupiterMintEntry(json, mint);
5596
- if (!row) {
5597
- console.debug(`[fetchJupiterSource] No price data from Jupiter for mint ${mint}`);
5598
- return null;
5599
- }
5123
+ if (!row) return null;
5600
5124
  return {
5601
5125
  type: "jupiter",
5602
5126
  address: mint,
@@ -5607,39 +5131,23 @@ async function fetchJupiterSource(mint, signal) {
5607
5131
  confidence: 40
5608
5132
  // Fallback — lower confidence
5609
5133
  };
5610
- } catch (err) {
5611
- console.warn(
5612
- `[fetchJupiterSource] Error fetching Jupiter data for mint ${mint}:`,
5613
- err instanceof Error ? err.message : String(err)
5614
- );
5134
+ } catch {
5615
5135
  return null;
5616
5136
  }
5617
5137
  }
5618
5138
  async function resolvePrice(mint, signal, options) {
5619
5139
  const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;
5620
5140
  const timeoutSignal = AbortSignal.timeout(timeoutMs);
5621
- const effectiveSignal2 = signal ? combineAbortSignals([signal, timeoutSignal]) : timeoutSignal;
5141
+ const combinedSignal = signal ? combineAbortSignals([signal, timeoutSignal]) : timeoutSignal;
5622
5142
  const [dexSources, jupiterSource] = await Promise.all([
5623
- fetchDexSources(mint, effectiveSignal2),
5624
- fetchJupiterSource(mint, effectiveSignal2)
5143
+ fetchDexSources(mint, combinedSignal),
5144
+ fetchJupiterSource(mint, combinedSignal)
5625
5145
  ]);
5626
5146
  const pythSource = lookupPythSource(mint);
5627
5147
  const allSources = [];
5628
5148
  if (pythSource) {
5629
- const dexPrice = dexSources[0]?.price ?? 0;
5630
- const jupPrice = jupiterSource?.price ?? 0;
5631
- if (dexPrice > 0 && jupPrice > 0) {
5632
- const mid = (dexPrice + jupPrice) / 2;
5633
- const deviation = Math.abs(dexPrice - jupPrice) / mid;
5634
- if (deviation > 0.5) {
5635
- pythSource.price = 0;
5636
- pythSource.confidence = 20;
5637
- } else {
5638
- pythSource.price = mid;
5639
- }
5640
- } else {
5641
- pythSource.price = dexPrice || jupPrice || 0;
5642
- }
5149
+ const refPrice = dexSources[0]?.price || jupiterSource?.price || 0;
5150
+ pythSource.price = refPrice;
5643
5151
  allSources.push(pythSource);
5644
5152
  }
5645
5153
  allSources.push(...dexSources);
@@ -5664,7 +5172,9 @@ export {
5664
5172
  ACCOUNTS_CLOSE_ACCOUNT,
5665
5173
  ACCOUNTS_CLOSE_SLAB,
5666
5174
  ACCOUNTS_CLOSE_STALE_SLABS,
5175
+ ACCOUNTS_CREATE_INSURANCE_MINT,
5667
5176
  ACCOUNTS_DEPOSIT_COLLATERAL,
5177
+ ACCOUNTS_DEPOSIT_INSURANCE_LP,
5668
5178
  ACCOUNTS_EXECUTE_ADL,
5669
5179
  ACCOUNTS_FUND_MARKET_INSURANCE,
5670
5180
  ACCOUNTS_INIT_LP,
@@ -5680,6 +5190,7 @@ export {
5680
5190
  ACCOUNTS_QUEUE_WITHDRAWAL,
5681
5191
  ACCOUNTS_RECLAIM_SLAB_RENT,
5682
5192
  ACCOUNTS_RESOLVE_MARKET,
5193
+ ACCOUNTS_SET_DEX_POOL,
5683
5194
  ACCOUNTS_SET_INSURANCE_ISOLATION,
5684
5195
  ACCOUNTS_SET_MAINTENANCE_FEE,
5685
5196
  ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK,
@@ -5698,22 +5209,17 @@ export {
5698
5209
  ACCOUNTS_UPDATE_CONFIG,
5699
5210
  ACCOUNTS_WITHDRAW_COLLATERAL,
5700
5211
  ACCOUNTS_WITHDRAW_INSURANCE,
5212
+ ACCOUNTS_WITHDRAW_INSURANCE_LP,
5701
5213
  AccountKind,
5702
5214
  CHAINLINK_ANSWER_OFFSET,
5703
5215
  CHAINLINK_DECIMALS_OFFSET,
5704
5216
  CHAINLINK_MIN_SIZE,
5705
- CHAINLINK_TIMESTAMP_OFFSET,
5706
5217
  CREATOR_LOCK_SEED,
5707
5218
  CTX_VAMM_OFFSET,
5708
5219
  DEFAULT_OI_RAMP_SLOTS,
5709
5220
  ENGINE_MARK_PRICE_OFF,
5710
5221
  ENGINE_OFF,
5711
5222
  IX_TAG,
5712
- LIGHTHOUSE_CONSTRAINT_ADDRESS,
5713
- LIGHTHOUSE_ERROR_CODES,
5714
- LIGHTHOUSE_PROGRAM_ID,
5715
- LIGHTHOUSE_PROGRAM_ID_STR2 as LIGHTHOUSE_PROGRAM_ID_STR,
5716
- LIGHTHOUSE_USER_MESSAGE,
5717
5223
  MARK_PRICE_EMA_ALPHA_E6,
5718
5224
  MARK_PRICE_EMA_WINDOW_SLOTS,
5719
5225
  MAX_DECIMALS,
@@ -5735,7 +5241,6 @@ export {
5735
5241
  RAMP_START_BPS,
5736
5242
  RAYDIUM_CLMM_PROGRAM_ID,
5737
5243
  RENOUNCE_ADMIN_CONFIRMATION,
5738
- RpcPool,
5739
5244
  SLAB_TIERS,
5740
5245
  SLAB_TIERS_V0,
5741
5246
  SLAB_TIERS_V1,
@@ -5757,14 +5262,11 @@ export {
5757
5262
  VAMM_MAGIC,
5758
5263
  ValidationError,
5759
5264
  WELL_KNOWN,
5760
- _internal,
5761
5265
  buildAccountMetas,
5762
5266
  buildAdlInstruction,
5763
5267
  buildAdlTransaction,
5764
5268
  buildIx,
5765
5269
  checkPhaseTransition,
5766
- checkRpcHealth,
5767
- classifyLighthouseError,
5768
5270
  clearStaticMarkets,
5769
5271
  computeDexSpotPriceE6,
5770
5272
  computeDynamicFeeBps,
@@ -5777,7 +5279,6 @@ export {
5777
5279
  computeLiqPrice,
5778
5280
  computeMarkPnl,
5779
5281
  computeMaxLeverage,
5780
- computeMaxWithdrawable,
5781
5282
  computePnlPercent,
5782
5283
  computePreTradeLiqPrice,
5783
5284
  computeRequiredMargin,
@@ -5785,15 +5286,14 @@ export {
5785
5286
  computeVammQuote,
5786
5287
  computeWarmupLeverageCap,
5787
5288
  computeWarmupMaxPositionSize,
5788
- computeWarmupProgress,
5789
5289
  computeWarmupUnlockedCapital,
5790
5290
  concatBytes,
5791
- countLighthouseInstructions,
5792
5291
  decodeError,
5793
5292
  decodeStakePool,
5794
5293
  depositAccounts,
5795
5294
  deriveCreatorLockPda,
5796
5295
  deriveDepositPda,
5296
+ deriveInsuranceLpMint,
5797
5297
  deriveKeeperFund,
5798
5298
  deriveLpPda,
5799
5299
  derivePythPriceUpdateAccount,
@@ -5830,11 +5330,14 @@ export {
5830
5330
  encodeClaimQueuedWithdrawal,
5831
5331
  encodeClearPendingSettlement,
5832
5332
  encodeCloseAccount,
5333
+ encodeCloseKeeperFund,
5833
5334
  encodeCloseOrphanSlab,
5834
5335
  encodeCloseSlab,
5835
5336
  encodeCloseStaleSlabs,
5337
+ encodeCreateInsuranceMint,
5836
5338
  encodeCreateLpVault,
5837
5339
  encodeDepositCollateral,
5340
+ encodeDepositInsuranceLP,
5838
5341
  encodeDepositLpCollateral,
5839
5342
  encodeExecuteAdl,
5840
5343
  encodeForceCloseResolved,
@@ -5905,6 +5408,7 @@ export {
5905
5408
  encodeUpdateRiskParams,
5906
5409
  encodeWithdrawCollateral,
5907
5410
  encodeWithdrawInsurance,
5411
+ encodeWithdrawInsuranceLP,
5908
5412
  encodeWithdrawInsuranceLimited,
5909
5413
  encodeWithdrawLpCollateral,
5910
5414
  fetchAdlRankedPositions,
@@ -5926,10 +5430,6 @@ export {
5926
5430
  initPoolAccounts,
5927
5431
  isAccountUsed,
5928
5432
  isAdlTriggered,
5929
- isAnchorErrorCode,
5930
- isLighthouseError,
5931
- isLighthouseFailureInLogs,
5932
- isLighthouseInstruction,
5933
5433
  isStandardToken,
5934
5434
  isToken2022,
5935
5435
  isValidChainlinkOracle,
@@ -5954,8 +5454,6 @@ export {
5954
5454
  simulateOrSend,
5955
5455
  slabDataSize,
5956
5456
  slabDataSizeV1,
5957
- stripLighthouseFromTransaction,
5958
- stripLighthouseInstructions,
5959
5457
  validateAmount,
5960
5458
  validateBps,
5961
5459
  validateI128,
@@ -5966,7 +5464,6 @@ export {
5966
5464
  validateU128,
5967
5465
  validateU16,
5968
5466
  validateU64,
5969
- withRetry,
5970
5467
  withdrawAccounts
5971
5468
  };
5972
5469
  //# sourceMappingURL=index.js.map